自定义View(英雄联盟七星图)_我好像被艾特了的博客-程序员宅基地

技术标签: 自定义View  LOL七星图  android  Android  

前两篇做了一下准备工作,现在开始正式进入我们的自定义View,采用第二种可动态计算多边形坐标的方案

一、观察及拆分UI图(假设是你们的UI设计师给你们的设计图?)

在这里插入图片描述

万事开头难,为了更好下手,我们先将其拆分,找最基础的开始着手

  1. 我们可以根据最前显示效果来拆分此view,我们先舍去文字、线条及红色线条,从它的正七边形背景来开始,从图中可以看出,此View相当于是四个不同的正七边形叠加而来,我们可以先绘制最大的正七边形,然后依次到最小的正七边形,当然要保证他们的中心点为同一个中心点,这样我们的正七边形背景就绘制好了;
  2. 绘制完我们的七边形背景后,根据绘制最前来反转绘制的话,现在应该来绘制不同的线条,由前两篇文章我们可以计算得到七边形的每个定点坐标,然后分别绘制中心点和七个顶点的连线,这样我们的简单连线就会治好来;
  3. 接下来我们可以绘制红色不规则七边形,我们可以把当作是一个正七边形来计算每个顶点坐标,只是每个顶点坐标的对应的正七边形外接圆的半径需要根据我们提供的能力占比来动态计算,然后在将这些顶点坐标连接起来就行来;
  4. 最后我们可以绘制对应能力的描述,当然此步骤可以在最外层的七边形坐标确定后即可绘制,或者是最外层七边形绘制完后进行绘制;

二、定义颜色和相关Power的字符串资源:

在上面我们确定来大致绘制流程后,接下来要准备一下我们需要用到的一些颜色和文字资源,我们可以使用AndroidStudio中自带的取色器来吸取4层七边形和线条对应的颜色:

  1. 从最外层的正七边形到最内层最小的七边形颜色分别为:

    	<color name="powerInfoViewInnerColor1">#D8EFF3</color>
        <color name="powerInfoViewInnerColor2">#A6DAE2</color>
        <color name="powerInfoViewInnerColor3">#70BEC4</color>
        <color name="powerInfoViewInnerColor4">#468690</color>
    
  2. 七条线条从最外侧到最内层的颜色为:

    	<color name="powerInfoViewLineColor1">#9CE1EA</color>
    	<color name="powerInfoViewLineColor2">#A3E3EE</color>
    	<color name="powerInfoViewLineColor3">#A3E3EE</color>
    	<color name="powerInfoViewLineColor4">#A3E3EE</color>
    
  3. 对应的字符串资源我们可以在View类中直接定义:

    private final String[] powerStr = {"击杀", "生存", "助攻", "物理", "魔法", "防御", "金钱"};
    

三、编写代码

到此我们正式进入我们的编码工作,按照上面定制的流程来编码;

  1. 创建我们的自定View类-PowerInfoView继承View

    public class PowerInfoView extends View {
        public PowerInfoView(Context context) {
            super(context);
        }
        public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
            super(context, attrs);
        }
        public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    }
    
  2. 根据view的绘制流程,我们下一步要对view的宽高来进行测量,重写view的onMeasure方法,对于:wrap_content 测量模式,暂不进行相关逻辑的设计,本人比较懒,还是将重点偏向于view的绘制渲染,如下:

    	@Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
            if (widthMeasureMode == MeasureSpec.EXACTLY) {
                viewWidth = MeasureSpec.getSize(widthMeasureSpec);
            } else {
                viewWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            if (heightMeasureMode == MeasureSpec.EXACTLY) {
                viewHeight = MeasureSpec.getSize(heightMeasureSpec);
            } else {
                viewHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
    
            setMeasuredDimension(viewWidth, viewHeight);
        }
    
  3. 在测量完我们的view的宽高,我们可以对view进行绘制工作来,重写我们的onDraw()方法:

    	@Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
        }
    
    1. 按照上面定制分离的绘制流程来进行绘制,现在我们开始绘制七边形背景,要绘制七边形我们先要计算处每个七边形的对应的坐标,根据前两篇文章介绍,我们需要知道对应的七边形外接圆的半径,因此我们先要计算出最外层的正七边形的外接圆的半径,然后取其对应的3/4、1/2/、1/4来计算出递减的正七边形外接圆半径,考虑到对应的文字的宽高和对应的padding属性分别影响我们七边的绘制位置(当然我们可以不计算padding属性,这样我们在设置padding属性的时候,就不会起作用),由于我们的对应的文字都是两个字,且文字距离距离七边形有一点段距离,我们取文字所占的宽高要稍微宽些,下面我们来初始化和计算目前用到的相关数值:

      		private int viewWidth; //view宽
      	    private int viewHeight;//view高
      	    private int heptagonRadio;//最外层外接圆半径
      	    private TextPaint mTextPaint;//绘制文字的画笔
      	    private double averageAngle;//对应准备工作中计算公式中的 β
      	    //七边形背景对应颜色
      	    private int[] powerInfoViewInnerColors = { //七边形背景对应颜色
      	            R.color.powerInfoViewInnerColor1,
      	            R.color.powerInfoViewInnerColor2,
      	            R.color.powerInfoViewInnerColor3,
      	            R.color.powerInfoViewInnerColor4
      	    };
      	    //线条对应颜色
      	    private int[] powerInfoViewLineColors = { 
      	            R.color.powerInfoViewLineColor1,
      	            R.color.powerInfoViewLineColor2,
      	            R.color.powerInfoViewLineColor3,
      	            R.color.powerInfoViewLineColor4
      	    };
      	    //对应能力文字
      	    private final String[] powerStr = {"击杀", "生存", "助攻", "物理", "魔法", "防御", "金钱"};
      	    //实际测量文字宽高
      	    private int textWidth, textHeight;
      	    public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
      	        super(context, attrs);
      	        this.init(context, attrs);//初始化相关属性
      	    }
      	
      	    public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs, int defStyleAttr) {
      	        super(context, attrs, defStyleAttr);
      	        this.init(context, attrs);//初始化相关属性
      	    }
      	
      	    private void init(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
      	        this.mTextPaint = new TextPaint();
      	        this.mTextPaint.setTextSize(50);
      			this.mTextPaint.setAntiAlias(true);
      	        this.averageAngle = 2 * Math.PI / heptagonSideNum;
      	    }
      

      接下来,初始化现阶段对应的属性后,开始计算我们最外层的半径,先测量文字原始的宽高:

      Rect rect = new Rect();
      this.mTextPaint.getTextBounds(powerStr[0], 0, powerStr[0].length(), rect);
      this.textHeight = rect.height();
      this.textWidth = rect.width();
      

      我们取对应文字宽度的5/4(this.textWidth * 5 / 4)作为文字绘制的宽度,文字高度为原始高度加上原始文字宽度的1/4(this.textHeight + this.textWidth * 1 / 4),然后我们分别用view的宽高减去对应的文字所占的宽高度,在减去对应的padding值,然后取最小值的一半来作为我们最外层外接圆半径:

      this.heptagonRadio = Math.min(viewWidth - getPaddingLeft() - getPaddingRight() - textWidth * 5 / 2, viewHeight - getPaddingTop() - getPaddingBottom() - textHeight * 2 + textWidth / 2) >> 1;
      

      这样我们最外层外接圆半径就计算出来来,结下分别取其对应的3/4、1/2、1/4即可,然后就是计算顶点坐标,在前两篇准备工作中,在计算坐标时,我们都需要对其进行平移,也就是加上对应的Δx 和 Δy,所以我们还需要计算出这两个值,其分别由paddingLeft 和 对应方位文字所占空间组成,所以得出:

      this.deltaX = getPaddingLeft() + textWidth * 5 / 4;
      this.deltaY = getPaddingTop() + textHeight + textWidth / 4;
      

      为了更好的计算和以面对对象的思维来进行编程,我们将对应的顶点封装成我们的多边形类如下:

      	public class Polygon implements Serializable {
      	
      	    private List<DoublePoint> mPointList;
      	    private final int polygonSideNum;
      	
      	    public Polygon(int polygonSideNum) {
      	        this.polygonSideNum = polygonSideNum;
      	        mPointList = new ArrayList<>(polygonSideNum);
      	    }
      	
      	    public Polygon(List<DoublePoint> pointList, int polygonSideNum) {
      	        if (pointList.size() != polygonSideNum) {
      	            throw new IllegalArgumentException("多边形参数异常!");
      	        }
      	        mPointList = pointList;
      	        this.polygonSideNum = polygonSideNum;
      	    }
      	
      	    public List<DoublePoint> getPointList() {
      	        return mPointList;
      	    }
      	
      	    public void setPointList(List<DoublePoint> pointList) {
      	        mPointList = pointList;
      	    }
      	
      	    public int getPolygonSideNum() {
      	        return polygonSideNum;
      	    }
      	
      	    /**
      	     * 从定义的定点逆时针旋转分别填充
      	     *
      	     * @param point
      	     */
      	    public void addPoint(DoublePoint point) {
      	        if (polygonSideNum == mPointList.size()) {
      	            throw new IllegalArgumentException("超过预定的多边形定点坐标!");
      	        }
      	        mPointList.add(point);
      	    }
      	
      	    public DoublePoint getPoint(int position) {
      	        if (position >= polygonSideNum || position < 0 || mPointList.isEmpty()) {
      	            return null;
      	        }
      	        return mPointList.get(position);
      	    }
      
      	     public void clearPoint() {//清除坐标集合
      			this.mPointList.clear();
      	     }
      
      	}
      
      

      和double数据类型的Point类:

      	public class DoublePoint {
      
          private double x;
          private double y;
      
          public DoublePoint() {
          }
      
          public DoublePoint(double x, double y) {
              this.x = x;
              this.y = y;
          }
      
          public double getX() {
              return x;
          }
      
          public void setX(double x) {
              this.x = x;
          }
      
          public double getY() {
              return y;
          }
      
          public void setY(double y) {
              this.y = y;
          }
      
      }
      	
      

      接下来创建一个几何来存储4个对应的七边形类,在init方法中初始化:

      		this.mPolygons = new ArrayList<>();
              this.mPolygons.add(new Polygon(heptagonSideNum));
              this.mPolygons.add(new Polygon(heptagonSideNum));
              this.mPolygons.add(new Polygon(heptagonSideNum));
              this.mPolygons.add(new Polygon(heptagonSideNum));
              this.dataPolygon = new Polygon(heptagonSideNum);
      

      做了这么工作终于到了计算对应七边形坐标了,创建 completeHeptagonPoint()方法来计算如下:

      		 private void completeHeptagonPoint() {
      			double currentRadio;
      	        double currentAngle;
      	        for (int i = 0; i < heptagonNum; i++) {
      	            Polygon polygon = mPolygons.get(i);
      	            polygon.clearPoint();//每次绘制要清空坐标,防止集合溢出异常
      	            currentRadio = (heptagonNum - i) * 1.0d / heptagonNum * heptagonRadio;
      	            for (int j = 0; j < heptagonSideNum; j++) {
      	                currentAngle = -Math.PI / 2 + j * averageAngle;
      	                polygon.addPoint(
      	                        new DoublePoint(
      	                                Math.cos(currentAngle) * currentRadio + heptagonRadio + deltaX,
      	                                Math.sin(currentAngle) * currentRadio + heptagonRadio + deltaY)
      	                );
      	            }
      	        }
      
      

      计算就不再讲解,前两篇文章已经讲过了,现在我们就开始绘制七边形背景了,创建绘制画笔,并在init方法中初始化(此处略,最后贴出最终代码),创建绘制方法,drawHeptagonBackground(canvas)代码为:

      	private void drawHeptagonBackground(Canvas canvas) {
      	        Path path = new Path();
      	        for (int i = 0; i < heptagonNum; i++) {
      	            mPaint.setColor(ContextCompat.getColor(getContext(), powerInfoViewInnerColors[i]));//变更颜色
      	            List<DoublePoint> pointList = mPolygons.get(i).getPointList();
      	            for (int j = 0; j < heptagonSideNum; j++) {
      	                DoublePoint doublePoint = pointList.get(j);
      	                if (j == 0) {
      	                    path.moveTo((float) doublePoint.getX(), (float) doublePoint.getY());
      	                } else {
      	                    path.lineTo((float) doublePoint.getX(), (float) doublePoint.getY());
      	                }
      	            }
      	            path.close();
      	            canvas.drawPath(path, mPaint);//绘制每一层七边形
      	            path.reset();//重置路径
      	        }
      	    }
      

      到此我们先来看一下运行效果吧,期待已久:
      在这里插入图片描述

  1. 在七边形背景绘制完成后我们来绘制,对应的线条,创建线条绘制方法:drawHeptagonLine(canvas)代码为:

        private void drawHeptagonLine(Canvas canvas) {
            float ox = heptagonRadio + deltaX;
            float oy = heptagonRadio + deltaY;
            for (int i = 0; i < heptagonNum; i++) {
                mPaint.setColor(ContextCompat.getColor(getContext(), powerInfoViewLineColors[i]));
                List<DoublePoint> pointList = mPolygons.get(i).getPointList();
                for (int j = 0; j < heptagonSideNum; j++) {
                    DoublePoint doublePoint = pointList.get(j);
                    canvas.drawLine(ox, oy, (float) doublePoint.getX(), (float) doublePoint.getY(), mPaint);
                }
            }
        }
    

    再次运行看一下效果:
    在这里插入图片描述

  2. 绘制文字,我们取文字宽度的1/4来作为文字和七边形的距离,分别绘制对应的文字,创建文字绘制方法drawHeptagonPowerStr(canvas)代码为:

        private void drawHeptagonPowerStr(Canvas canvas) {
    
            List<DoublePoint> pointList = mPolygons.get(0).getPointList();
    
            DoublePoint doublePoint = pointList.get(0);
    
            canvas.drawText(powerStr[0], (float) (doublePoint.getX() - textWidth / 2), (float) (doublePoint.getY() - textWidth / 4), mTextPaint);
    
            doublePoint = pointList.get(1);
    
            canvas.drawText(powerStr[1], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() - mTextPaint.descent()), mTextPaint);
    
            doublePoint = pointList.get(2);
    
            canvas.drawText(powerStr[2], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() + textHeight / 2), mTextPaint);
    
            doublePoint = pointList.get(3);
    
            canvas.drawText(powerStr[3], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() - mTextPaint.ascent()), mTextPaint);
    
            doublePoint = pointList.get(4);
    
            canvas.drawText(powerStr[4], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() - mTextPaint.ascent()), mTextPaint);
    
            doublePoint = pointList.get(5);
    
            canvas.drawText(powerStr[5], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() + textHeight / 2), mTextPaint);
    
            doublePoint = pointList.get(6);
    
            canvas.drawText(powerStr[6], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() - mTextPaint.descent()), mTextPaint);
    
    
        }
    
    

    在运行来看一下运行结果:
    在这里插入图片描述

  3. 最终绘制对应数据能力所占的百分比,创建double型集合存储对应的数据占比private List<Double> dataPercents;,我们并不对其进行初始化,通过set方法来动态的初始化数据,然后重新绘制:

        public void setDataPercents(List<Double> dataPercents) {
            this.dataPercents = dataPercents;
            invalidate();
        }
    

    在得到对应能力百分比值时,我们开始计算我们的每个能力值所对应的的坐标,在方法completeHeptagonPoint添加代码:

    if (dataPercents != null) {
                dataPolygon.clearPoint();//清除上次对应的坐标防止集合溢出异常
                for (int j = 0; j < heptagonSideNum; j++) {
                    currentRadio = dataPercents.get(j) * heptagonRadio;
                    currentAngle = -Math.PI / 2 + j * averageAngle;
                    dataPolygon.addPoint(
                            new DoublePoint(
                                    Math.cos(currentAngle) * currentRadio + heptagonRadio + deltaX,
                                    Math.sin(currentAngle) * currentRadio + heptagonRadio + deltaY));
                }
            }
    

    而在ondraw方法中绘制时,我们要对数据源进行判断,若没有初始化(判空)则不进行绘制,创建我们的数据绘制方法drawPercentHeptagon(canvas),具体代码如下:

        private void drawPercentHeptagon(Canvas canvas) {
            Path path = new Path();
            mPaint.setColor(Color.RED);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(10);
            List<DoublePoint> pointList = dataPolygon.getPointList();
            for (int j = 0; j < heptagonSideNum; j++) {
                DoublePoint doublePoint = pointList.get(j);
                if (j == 0) {
                    path.moveTo((float) doublePoint.getX(), (float) doublePoint.getY());
                } else {
                    path.lineTo((float) doublePoint.getX(), (float) doublePoint.getY());
                }
            }
            path.close();
            canvas.drawPath(path, mPaint);
        }
    
       ```
    

在此运行:
在这里插入图片描述
在这里插入图片描述
红色的不规则七边形呢?别着急我们还没对其进行初始化呢,我们在MainActivity中创建数据源,使用随机double方法,然后对其动态赋值:

        List<Double> list = new ArrayList<>();

        for (int i = 0; i < 7; i++) {
            list.add(Math.random());
        }
        mPowerInfoView2.setDataPercents(list);

再次运行(随机了一个相对好看相对规则的哈哈):
在这里插入图片描述

至此,我们自定义View(英雄联盟七星图)就完成,如果什么不对或者更好的方法理解可以留言给我谢谢!下面贴出整个代码:

public class PowerInfoView extends View {


    private int viewWidth;
    private int viewHeight;
    private int heptagonRadio;
    private Paint mPaint;
    private TextPaint mTextPaint;
    private final int heptagonSideNum = 7;
    private final int heptagonNum = 4;
    private List<Polygon> mPolygons;
    private Polygon dataPolygon;
    private double averageAngle;
    private int[] powerInfoViewInnerColors = {
            R.color.powerInfoViewInnerColor1,
            R.color.powerInfoViewInnerColor2,
            R.color.powerInfoViewInnerColor3,
            R.color.powerInfoViewInnerColor4
    };
    private int[] powerInfoViewLineColors = {
            R.color.powerInfoViewLineColor1,
            R.color.powerInfoViewLineColor2,
            R.color.powerInfoViewLineColor3,
            R.color.powerInfoViewLineColor4
    };
    private List<Double> dataPercents;
    private final String[] powerStr = {"击杀", "生存", "助攻", "物理", "魔法", "防御", "金钱"};
    private int textWidth, textHeight;
    private int deltaX, deltaY;

    public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
        super(context, attrs);
        this.init(context, attrs);
    }

    public PowerInfoView(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.init(context, attrs);
    }

    private void init(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
        this.mPaint = new Paint();
        this.mPaint.setAntiAlias(true);
        this.mPaint.setColor(Color.BLUE);
        this.mTextPaint = new TextPaint();
        this.mTextPaint.setTextSize(50);
        this.mTextPaint.setAntiAlias(true);
        this.mPolygons = new ArrayList<>();
        this.mPolygons.add(new Polygon(heptagonSideNum));
        this.mPolygons.add(new Polygon(heptagonSideNum));
        this.mPolygons.add(new Polygon(heptagonSideNum));
        this.mPolygons.add(new Polygon(heptagonSideNum));
        this.dataPolygon = new Polygon(heptagonSideNum);
        this.averageAngle = 2 * Math.PI / heptagonSideNum;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        Rect rect = new Rect();
        this.mTextPaint.getTextBounds(powerStr[0], 0, powerStr[0].length(), rect);
        this.textHeight = rect.height();
        this.textWidth = rect.width();
        this.deltaX = getPaddingLeft() + textWidth * 5 / 4;
        this.deltaY = getPaddingTop() + textHeight + textWidth / 4;
        this.heptagonRadio = Math.min(viewWidth - getPaddingLeft() - getPaddingRight() - textWidth * 5 / 2, viewHeight - getPaddingTop() - getPaddingBottom() - textHeight * 2 + textWidth / 2) >> 1;

        //completeHeptagonPoint
        completeHeptagonPoint();
        //绘制七边形背景
        drawHeptagonBackground(canvas);
        //绘制七边形Line
        drawHeptagonLine(canvas);

        drawHeptagonPowerStr(canvas);

        //绘制数据显示的七边形
        if (dataPercents != null) {
            drawPercentHeptagon(canvas);
        }
    }

    /**
     * 绘制powerStr
     *
     * @param canvas
     */
    private void drawHeptagonPowerStr(Canvas canvas) {

        List<DoublePoint> pointList = mPolygons.get(0).getPointList();

        DoublePoint doublePoint = pointList.get(0);

        canvas.drawText(powerStr[0], (float) (doublePoint.getX() - textWidth / 2), (float) (doublePoint.getY() - textWidth / 4), mTextPaint);

        doublePoint = pointList.get(1);

        canvas.drawText(powerStr[1], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() - mTextPaint.descent()), mTextPaint);

        doublePoint = pointList.get(2);

        canvas.drawText(powerStr[2], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() + textHeight / 2), mTextPaint);

        doublePoint = pointList.get(3);

        canvas.drawText(powerStr[3], (float) (doublePoint.getX() + textWidth / 4), (float) (doublePoint.getY() - mTextPaint.ascent()), mTextPaint);

        doublePoint = pointList.get(4);

        canvas.drawText(powerStr[4], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() - mTextPaint.ascent()), mTextPaint);

        doublePoint = pointList.get(5);

        canvas.drawText(powerStr[5], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() + textHeight / 2), mTextPaint);

        doublePoint = pointList.get(6);

        canvas.drawText(powerStr[6], (float) (doublePoint.getX() - textWidth * 5 / 4), (float) (doublePoint.getY() - mTextPaint.descent()), mTextPaint);


    }

    /**
     * 绘制对应数据形成的七边形
     *
     * @param canvas
     */
    private void drawPercentHeptagon(Canvas canvas) {
        Path path = new Path();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);
        List<DoublePoint> pointList = dataPolygon.getPointList();
        for (int j = 0; j < heptagonSideNum; j++) {
            DoublePoint doublePoint = pointList.get(j);
            if (j == 0) {
                path.moveTo((float) doublePoint.getX(), (float) doublePoint.getY());
            } else {
                path.lineTo((float) doublePoint.getX(), (float) doublePoint.getY());
            }
        }
        path.close();
        canvas.drawPath(path, mPaint);
    }

    /**
     * 计算对应七边形的定点坐标
     */
    private void completeHeptagonPoint() {
        double currentRadio;
        double currentAngle;
        for (int i = 0; i < heptagonNum; i++) {
            Polygon polygon = mPolygons.get(i);
            polygon.clearPoint();
            currentRadio = (heptagonNum - i) * 1.0d / heptagonNum * heptagonRadio;
            for (int j = 0; j < heptagonSideNum; j++) {
                currentAngle = -Math.PI / 2 + j * averageAngle;
                polygon.addPoint(
                        new DoublePoint(
                                Math.cos(currentAngle) * currentRadio + heptagonRadio + deltaX,
                                Math.sin(currentAngle) * currentRadio + heptagonRadio + deltaY)
                );
            }
        }
        if (dataPercents != null) {
            dataPolygon.clearPoint();
            for (int j = 0; j < heptagonSideNum; j++) {
                currentRadio = dataPercents.get(j) * heptagonRadio;
                currentAngle = -Math.PI / 2 + j * averageAngle;
                dataPolygon.addPoint(
                        new DoublePoint(
                                Math.cos(currentAngle) * currentRadio + heptagonRadio + deltaX,
                                Math.sin(currentAngle) * currentRadio + heptagonRadio + deltaY));
            }
        }
    }

    /**
     * 绘制七边形Line
     *
     * @param canvas
     */
    private void drawHeptagonLine(Canvas canvas) {
        float ox = heptagonRadio + deltaX;
        float oy = heptagonRadio + deltaY;
        for (int i = 0; i < heptagonNum; i++) {
            mPaint.setColor(ContextCompat.getColor(getContext(), powerInfoViewLineColors[i]));
            List<DoublePoint> pointList = mPolygons.get(i).getPointList();
            for (int j = 0; j < heptagonSideNum; j++) {
                DoublePoint doublePoint = pointList.get(j);
                canvas.drawLine(ox, oy, (float) doublePoint.getX(), (float) doublePoint.getY(), mPaint);
            }
        }
    }

    /**
     * 绘制七边形背景
     *
     * @param canvas
     */
    private void drawHeptagonBackground(Canvas canvas) {
        Path path = new Path();
        for (int i = 0; i < heptagonNum; i++) {
            mPaint.setColor(ContextCompat.getColor(getContext(), powerInfoViewInnerColors[i]));
            List<DoublePoint> pointList = mPolygons.get(i).getPointList();
            for (int j = 0; j < heptagonSideNum; j++) {
                DoublePoint doublePoint = pointList.get(j);
                if (j == 0) {
                    path.moveTo((float) doublePoint.getX(), (float) doublePoint.getY());
                } else {
                    path.lineTo((float) doublePoint.getX(), (float) doublePoint.getY());
                }
            }
            path.close();
            canvas.drawPath(path, mPaint);
            path.reset();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMeasureMode == MeasureSpec.EXACTLY) {
            viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        } else {
            viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        }
        if (heightMeasureMode == MeasureSpec.EXACTLY) {
            viewHeight = MeasureSpec.getSize(heightMeasureSpec);
        } else {
            viewHeight = MeasureSpec.getSize(heightMeasureSpec);
        }

        setMeasuredDimension(viewWidth, viewHeight);
    }


    public void setDataPercents(List<Double> dataPercents) {
        this.dataPercents = dataPercents;
        invalidate();
    }

}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33225399/article/details/90520867

智能推荐

Android 技术之为RecyclerView添加item的点击事件_可爱养眼的博客-程序员宅基地

RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一下观察者模式。最终目的模拟ListView的setOnItemClickListener()方法,调用者只须调用类似于setOnItemClickListener的东西就能获得被点击item的相关数据。

navicate导入sql时出现错误error:1300 - Invalid utf8 character string: 'D7D4D4'_schoolblack的博客-程序员宅基地

navicate导入sql时出现错误error:1300 - Invalid utf8 character string: ‘D7D4D4’powerdesign生成的sql文件,导入不了。根据错误提示可以看出,大概是中午乱码的原因出现某些“或/符号识别不了,但是找了半天comment注释中并无,所以解决不了。结果:然后发现导入信息中中文乱码,这是导致报错的主要原因,中文编码格式出了错。...

Torch Threads_wangfenghui132的博客-程序员宅基地

Torch Threads最近在读openface源码的时候,对里面的线程不怎么清楚。然后就到github上读了下说明。Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传LaTex数学公式UML序列图和流程图离线写博客导入导出Markdown文件丰富的快捷键简介你可能会想为什么另外开发一个基于lua的线程包?其实就我所知,目前存在的线程包作用十分有限,仅仅

2019年9月全国程序员工资统计_代码技巧的博客-程序员宅基地

来自:CSDN,作者:有数可据链接:https://blog.csdn.net/juwikuang/article/details/100551050主要城市程序员工资2...

RxBus 一个简易、非反射的Android事件通知库_xuexiangjys的博客-程序员宅基地

RxBus 一个简易的Android事件通知库,使用RxJava和Javassist设计,拒绝使用反射,保证性能高效稳定。 该项目是从RxUtil中分离出RxBus相关,并进行功能增强。如果你对RxJava的使用还不满足于RxBus, 你可以移步RxUtil和RxUtil2。关于我 特征支持多事件定义。支持自定义数据携带。支持全局和局部的事件订...

随便推点

图形学基础知识:光栅化和采样_王王王渣渣的博客-程序员宅基地_图形学 采样

在前面的学习中,我们已经可以通过MVP变换,把摄像机观测的物体都压缩成了一个标准立方体,接下来我们要做的是把这个标准立方体绘制到屏幕(Screen)上何为屏幕?一个二维数组,每个元素称之为像素(pixel,picture element的缩写),例如我们常说的屏幕分辨率1920*1080,就是说有这么些个像素。屏幕是一个典型的光栅成像设备。光栅(Raster)在德语中就是屏幕的意思,光栅化(Rasterize,名变动)就是把东西画在屏幕上。像素,最小单位,像素内的颜色可以用rgba来定义,一

qcom camera XXXX_lib.h的驱动文件配置_wing12345678910的博客-程序员宅基地

#define START_REG_ARRAY \{ \  {0xfe, 0x00, 0x00}, \}#define STOP_REG_ARRAY \{ \  {0xfe, 0x00, 0x00}, \}#define GROUPON_REG_ARRAY \{ \   {0xfe, 0x00, 0x00}, \}#define GROUPOFF_REG_ARRAY \{ \   {0xfe, 0...

读不读博士?不适合读博士的人选择读博士了怎么办?_小铁匠-Ma的博客-程序员宅基地

读不读博士?不适合读博士的人选择读博士了怎么办?有人说:努力重要,选择更重要。也有人说:三分天注定,七分靠打拼。关于努力和选择谁更重要的话题相信是仁者见仁、智者见智。而我,选来选去,最终选上一条本科怎么都想不到的道路,科研道路,成为了一名理工科博士。从小学开始,我就是个文艺骨干,板报、拉丁、合唱指挥、书法都能在学校有所展示,自己也有很高的热情和动力。一直到现在都一样,对文化活动有种天然的亲...

NSOperation-NSBlockOperation_yxcharles的博客-程序员宅基地

- (void)test { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"---- download%@",[NSThread currentThread]); }]; [operation addExecutionBlock:

Mybatis系列十二:逆向工程MBG_苍穹尘的博客-程序员宅基地

 MyBatis Generator: 简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。支持基本的增删 改查,以及QBC风格的条件查询。但是表连接、 存储过程等这些复杂sql的定义需要我们手工编写。官方文档地址:http://www.mybatis.org/generator/官方工程地址:https://githu...