Path我就写一篇(更新:添加圆形表格实现,2018.10.26)

我就一篇写完Path几乎所有的用法,有点长,请细心看
 

先贴出GcsSloop大神整理的Path函数图片(ps:Android5.0以上的方法,他没整理)

直接来正题,创建自定义View,创建画笔设置颜色

public class MyView extends View {
    private int mWidth;
    private int mHeight;
    private Paint mPaint;

    public MyView(Context context){
        this(context,null);
    }

    public MyView(Context context, AttributeSet attrs){
        super(context,attrs);
        
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
    }

    @Override
    protected void onSizeChanged(int w,int h,int oldw,int oldh){
        super.onSizeChanged(w,h,oldw,oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//画画

    }
}

 

注意:Path对点的顺序很重要

 

 

1.划直线和移动点,moveTo、 setLastPoint、 lineTo 和 close

 

// 移动坐标系到屏幕中心
        canvas.translate(mWidth / 2, mHeight / 2); 
        Path path = new Path();
        //从上一次的点到指定的点划直线,这个时候上一次的点是原始点,坐标是(0,0)
        path.lineTo(100,100);
        //移动最新的点的位置,不影响上一次的操作
        path.moveTo(200,200);
        //划线
        path.lineTo(100,200);
        //移动最新的点,影响上一次的操作
        path.setLastPoint(200,100);
        //如果把起始点和最新的点连线,整个图案能够封闭起来,就连线,否则就不连线
        path.close();
        //画出来
        canvas.drawPath(path,mPaint);

 

 

这个时候close函数没有用,必须把moveTo函数去掉才行

2.相对距离画画

都是把最新的点的坐标当做坐标轴来计算自己的位置的

        canvas.translate(centerX / 2, centerY / 2);
        Path path = new Path();
        path.rLineTo(100,100);
        path.rMoveTo(0,100);
        path.rCubicTo(100,100,100,200,300,100);
        path.rQuadTo(200,100,100,200);
        //画出来
        canvas.drawPath(path,mPaint);

 

 

 

3.基本形状

// 圆形
public void addCircle (float x, float y, float radius, Path.Direction dir)
// 椭圆
public void addOval (RectF oval, Path.Direction dir)
// 矩形
public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
public void addRect (RectF rect, Path.Direction dir)
// 圆角矩形
public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)

 

顺时针和逆时针

 

    public enum Direction {
        /** clockwise */
        CW  (0),    // must match enum in SkPath.h
        /** counter-clockwise */
        CCW (1);    // must match enum in SkPath.h

    }

 

框子类,你就当他是从左上角开始顺时针或者逆时针到右下角画矩形,基本形状都是贴着这个框来画的,左上角的坐标是(left,top),右下角(right,bottom)。(ps:注意他会影响到点的绘画顺序)

 

public RectF(float left, float top, float right, float bottom)

 

画个米老鼠

 

        canvas.translate(mWidth / 2, mHeight / 2);  // 移动坐标系到屏幕中心
        Path path = new Path();
        path.addRect(-200,-200,200,200, Path.Direction.CW);
        path.addCircle(-200,-200,100, Path.Direction.CW);
        path.addCircle(200,-200,100, Path.Direction.CW);
        canvas.drawPath(path,mPaint);

 

 

画圆弧

addArc :    直接添加一个圆弧到path中
arcTo     :添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点
这是开始角度和需要画的圆弧大小    
public void addArc(RectF oval, float startAngle, float sweepAngle)

画一个

        canvas.translate(mWidth / 2, mHeight / 2);  // 移动坐标系到屏幕中心
        Path path = new Path();
        RectF oval = new RectF(0,0,300,300);
        path.addArc(oval,270,270);
        canvas.drawPath(path,mPaint);

 

 

 

4.贝塞尔曲线

就是有了它计算机才能各种曲线。
想知道具体贝塞尔的原理就看看这个博客,http://www.gcssloop.com/customview/Path_Bezier

借一下GcsSloop的图,这是二阶贝塞尔曲线



通过移动一条线首尾移动到下一个点,而这条线上也有一个点从首部移动到尾部,两个移动都是匀速、并且同时开始和到达终点,

对于三阶贝塞尔曲线能够由二阶贝塞尔曲线所组成,而且更高阶的也可以,所以我们针对二阶说

首先贴出一个GcsSloop画二阶贝塞尔曲线的自定义View代码

public class MyView extends View {

    private Paint mPaint;
    private int centerX, centerY;

    private PointF start, end, control;

    public MyView(Context context) {
        super(context);
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(60);

        start = new PointF(0,0);
        end = new PointF(0,0);
        control = new PointF(0,0);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w/2;
        centerY = h/2;

        // 初始化数据点和控制点的位置
        start.x = centerX-200;
        start.y = centerY;
        end.x = centerX+200;
        end.y = centerY;
        control.x = centerX;
        control.y = centerY-100;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 根据触摸位置更新控制点,并提示重绘
        control.x = event.getX();
        control.y = event.getY();
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制数据点和控制点
        mPaint.setColor(Color.GRAY);
        mPaint.setStrokeWidth(20);
        canvas.drawPoint(start.x,start.y,mPaint);
        canvas.drawPoint(end.x,end.y,mPaint);
        canvas.drawPoint(control.x,control.y,mPaint);

        // 绘制辅助线
        mPaint.setStrokeWidth(4);
        canvas.drawLine(start.x,start.y,control.x,control.y,mPaint);
        canvas.drawLine(end.x,end.y,control.x,control.y,mPaint);

        // 绘制贝塞尔曲线
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(8);

        Path path = new Path();

        path.moveTo(start.x,start.y);
        path.quadTo(control.x,control.y,end.x,end.y);

        canvas.drawPath(path, mPaint);
    }
}

 

再用一下它的图



接下来就得我自己做个新东西了,我用四根贝塞尔曲线做一个不断的膨胀和收缩的正方体、

 

这是我自己写的代码,高兴

public class MyView extends View {

    private Paint mPaint;
    private int centerX, centerY;

    int bottom_x,bottom_y,left_x,left_y,top_x,top_y,right_x,right_y;

    private int time = 1000;
    private int sum = 0;
    private int max_sum = 50;
    private int state = 0;
    public MyView(Context context) {
        super(context);
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(60);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w/2;
        centerY = h/2;


        // 初始化数据点和控制点的位置


        bottom_x = centerX - 200;
        bottom_y = centerY + 200;

        left_x = centerX - 200;
        left_y = centerY - 200;

        top_x = centerX + 200;
        top_y = centerY - 200;

        right_x = centerX + 200;
        right_y = centerY +200;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        // 绘制贝塞尔曲线
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);

        Path path_bottom = new Path();
        path_bottom.moveTo(bottom_x,bottom_y);
        path_bottom.quadTo(0+centerX ,bottom_y+ 200/50*sum,200+centerX,bottom_y);
        canvas.drawPath(path_bottom, mPaint);

        Path path_left = new Path();
        path_left.moveTo(left_x,left_y);
        path_left.quadTo(left_x - 200/50*sum,0+centerY,bottom_x,bottom_y);
        canvas.drawPath(path_left, mPaint);

        Path path_top = new Path();
        path_top.moveTo(top_x,top_y);
        path_top.quadTo(0 +centerX,top_y- 200/50*sum,left_x,left_y);
        canvas.drawPath(path_top, mPaint);

        Path path_right = new Path();
        path_right.moveTo(right_x,right_y);
        path_right.quadTo(right_x+ 200/50*sum ,0+centerY,right_x,top_y);
        canvas.drawPath(path_right, mPaint);

        if(state == 0){
            if(sum < 50){
                sum++;
            }else {
                sum --;
                state = 1;
            }

        }

        if(state == 1){
            if(sum > -50){
                sum--;
            }else {
                sum ++;
                state = 0;
            }
        }



        postInvalidateDelayed( time/max_sum);
    }
}

 

本来应该是动图的,但我不会在真机上录gif图

 

 

5.填充颜色


首先填充目标是封闭的图形,这就关系到系统判断是否封闭的方法了,还是用的GcsSloop的表

非零环绕数规则说的左右,你不用太在意,你可以随便设定射线的一边为左右就可以了

    public enum FillType {
        // these must match the values in SkPath.h
        /**
         * Specifies that "inside" is computed by a non-zero sum of signed
         * edge crossings.
         */
        WINDING         (0),
        /**
         * Specifies that "inside" is computed by an odd number of edge
         * crossings.
         */
        EVEN_ODD        (1),
        /**
         * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
         */
        INVERSE_WINDING (2),
        /**
         * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
         */
        INVERSE_EVEN_ODD(3);

    }

 

对于非零环绕数规则,绘画的顺时针和逆时针对其会有很大的影响,而奇偶计数法没有关系

下面的画了三个正方形,他们随着Direction的值变化,填充的结果也会变化

 

        mPaint.setStyle(Paint.Style.FILL);                   // 设置画笔模式为填充

        canvas.translate(centerX, centerY);          // 移动画布(坐系)

        Path path = new Path();                                     // 创建Path
        path.addRect(-100, -100, 100, 100, Path.Direction.CW);
        path.addRect(-200, -200, 200, 200, Path.Direction.CW);
        path.addRect(-400, -400, 400, 400, Path.Direction.CW);

        path.setFillType(Path.FillType.WINDING);                    // 设置Path填充模式为非零环绕规则

        canvas.drawPath(path, mPaint);                       // 绘制Path

 

 

 

6.布尔操作

就是差集、交集、并集、异或

    public enum Op {
        /**
         * Subtract the second path from the first path.
         */
        DIFFERENCE,
        /**
         * Intersect the two paths.
         */
        INTERSECT,
        /**
         * Union (inclusive-or) the two paths.
         */
        UNION,
        /**
         * Exclusive-or the two paths.
         */
        XOR,
        /**
         * Subtract the first path from the second path.
         */
        REVERSE_DIFFERENCE
    }

 

写个两个圆的差集,这个差集得到是path1减去path2与path1共有的部分

 

        canvas.translate(centerX, centerY);
        Path path1 = new Path();
        Path path2 = new Path();
        path1.addCircle(100, 0, 200, Path.Direction.CW);
        path2.addCircle(-100, 0, 200, Path.Direction.CW);
        path1.op(path2, Path.Op.DIFFERENCE);
        canvas.drawPath(path1, mPaint);

 

 

 

记得还有翻转差集,能得到path2减去path1与path2的共有

 

path1.op(path2, Path.Op.REVERSE_DIFFERENCE);

 

 

7.PaintMeasure


PaintMeasure能够获取Paint的一些信息,比如:长度、是否闭合等、最重要的是它能够截取Path的片段然后你就可以画出来。

还是用GcsSloop的整理的表

我要画一个环形进度条,下面是完成

我们需要画一个灰色的圆环作为底部

        mPaint.setStrokeWidth(20);
        mPaint.setColor(getResources().getColor(R.color.circle_gray));
        Path path_circle = new Path();
        path_circle.addCircle(0,0,radius, Path.Direction.CW);
        canvas.drawPath(path_circle,mPaint);

 

然后再画圆弧,这个圆弧通过PathMeasure设置截取开始位置和截取长度来截取一个圆环得来

 

        mPaint.setStrokeWidth(20);
        mPaint.setColor(getResources().getColor(R.color.circle_orange));
        Path path_orange_dst = new Path();
        Path path_orange = new Path();
        path_orange.addCircle(0,0,radius, Path.Direction.CW);
        PathMeasure measure = new PathMeasure(path_orange, false);         // 将 Path 与 PathMeasure 关联

measure.getSegment((float) (radius*1.5 * Math.PI), (float) (radius*(2) * Math.PI), path_orange_dst, true);

        canvas.drawPath(path_orange_dst,mPaint);

 

这里要注意,截取圆环,你只能0到2,但是这里进度条为0时,是从坐标为(0,200)开始顺时针开始截取的,而这个圆环是从坐标为(200,0)开始的,这就很尴尬了,然后设置截取的开始位置和长度这两者加起来不能超过这个圆环的长度也就是 2*radius*PI

所以

 

        if(progress <= 25){
            measure.getSegment((float) (radius*1.5 * Math.PI), (float) (radius*(1.5 + progress/100.0 * 2) * Math.PI), path_orange_dst, true);
        }else {
            measure.getSegment((float) (radius*1.5 * Math.PI), (float) (radius*(2.0) * Math.PI), path_orange_dst, true);

            measure.getSegment((float) (0 * Math.PI), (float) (radius * ((progress - 25)/100.0 * 2 ) * Math.PI), path_orange_dst, true);
        }

 

这里注意progress是进度,1到100
 

 

完整代码如下

public class MyView extends View {
    private int mWidth;
    private int mHeight;
    private Paint mPaint;
    private int progress = 50;
    private int radius = 200;
    private int time = 10000;
    private int max_progress = 100;
    public MyView(Context context){
        this(context,null);
    }

    public MyView(Context context, AttributeSet attrs){
        super(context,attrs);

        mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.circle_gray));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(20);
        mPaint.setTextSize(80);

    }

    @Override
    protected void onSizeChanged(int w,int h,int oldw,int oldh){
        super.onSizeChanged(w,h,oldw,oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//画画
        canvas.translate(mWidth / 2, mHeight / 2);  // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)

        mPaint.setStrokeWidth(20);
        mPaint.setColor(getResources().getColor(R.color.circle_gray));
        Path path_circle = new Path();
        path_circle.addCircle(0,0,radius, Path.Direction.CW);
        canvas.drawPath(path_circle,mPaint);

        mPaint.setStrokeWidth(20);
        mPaint.setColor(getResources().getColor(R.color.circle_orange));
        Path path_orange_dst = new Path();
        Path path_orange = new Path();
        path_orange.addCircle(0,0,radius, Path.Direction.CW);
        PathMeasure measure = new PathMeasure(path_orange, false);         // 将 Path 与 PathMeasure 关联
        if(progress <= 25){
            measure.getSegment((float) (radius*1.5 * Math.PI), (float) (radius*(1.5 + progress/100.0 * 2) * Math.PI), path_orange_dst, true);
        }else {
            measure.getSegment((float) (radius*1.5 * Math.PI), (float) (radius*(2.0) * Math.PI), path_orange_dst, true);

            measure.getSegment((float) (0 * Math.PI), (float) (radius * ((progress - 25)/100.0 * 2 ) * Math.PI), path_orange_dst, true);
        }
        canvas.drawPath(path_orange_dst,mPaint);


        mPaint.setStrokeWidth(0);
        mPaint.setColor(Color.BLACK);
        canvas.drawText(progress + "%", -50, 10, mPaint);


        Log.v("zzw",progress+"");

        if (progress < max_progress) {
            progress++;

        }else {
            progress = 0;
        }
        postInvalidateDelayed(time/max_progress);
    }
}

 

8.Region

 

Region区域,它能够判断某个坐标是否在某个区域里,就算这个区域是不规则的。

首先要使用它,需要创建的时候放一个大的范围,w和h是这个自定义View的宽高,这个范围还不是这个Region规定的区域范围

Region globalRegion = new Region( -w, -h, w, h);

 

将某个闭合的path作为这个区域的范围

 

circleRegion.setPath(circlePath,globalRegion);

 

判断某个坐标是否在这个区域内

 

circleRegion.contains(x, y)

 

这样就完了,我下面贴一个剑型按钮的代码,手指放在剑上面剑会变红色,手机抬起回复成黑色。

 

public class CustomView extends View {

    /**
     * the context of current view
     */
    protected Context mCurrentContext;

    /**
     * the width of current view.
     */
    protected int mViewWidth;

    /**
     * the height of current view.
     */
    protected int mViewHeight;

    /**
     * default Paint.
     */
    protected Paint mDeafultPaint = new Paint();

    /**
     * default TextPaint
     */
    protected TextPaint mDefaultTextPaint = new TextPaint();


    public CustomView(Context context) {
        this(context, null);
    }

    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mCurrentContext = context;
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHeight = h;
    }


}

 

public class RegionClickView extends CustomView {

    static final int state_normal = 1;
    static final int state_click = 2;
    int state = 0;
    Region circleRegion;
    Path circlePath;
    public RegionClickView(Context context) {
        super(context);
        mDeafultPaint.setColor(0xFF4E5268);
        circlePath = new Path();
        circleRegion = new Region();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);


        circlePath.moveTo(-40 + w/2, 600 + h/2-300);
        circlePath.rLineTo(0,  160);
        circlePath.rLineTo(-80,0);
        circlePath.rLineTo(0, -40);
        circlePath.rLineTo(80, 0);
        circlePath.rLineTo(0, -900);
        circlePath.rLineTo(40,  -100);
        circlePath.rLineTo(40, 100);
        circlePath.rLineTo(0, 900);
        circlePath.rLineTo(80, 0);
        circlePath.rLineTo(0, 40);
        circlePath.rLineTo(-80, 0);
        circlePath.rLineTo(0, 160);
        circlePath.rLineTo(-80, 0);

        Region globalRegion = new Region( -w, -h, w, h);
        circleRegion.setPath(circlePath,globalRegion);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                int x = (int) event.getX();
                int y = (int) event.getY();
                if (circleRegion.contains(x, y)){
                    state = state_click;
                    invalidate();
                }
                break;

            case MotionEvent.ACTION_UP:
                state = state_normal;
                invalidate();
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(state == state_click){
            mDeafultPaint.setColor(getResources().getColor(R.color.circle_red));
        }else {
            mDeafultPaint.setColor(getResources().getColor(R.color.circle_black));
        }

        Path circle = circlePath;
        canvas.drawPath(circle,mDeafultPaint);
    }
}

 

效果图

 

 

圆形表格

 

package bitpai.com.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import bitpai.com.two.R;

public class MyView extends View {

    List<Data> data=new ArrayList<>();
    int mWidth,mHeight;
    Paint paint;
    Paint linePaint;
    Paint textPaint;
    Context context;
    int strokeWidth=50;
    int circleWidth=270;
    int slantLineLenght=60;
    int straightLineLenght=200;
    int lineOffSet=2;
    int lineWidth=10;
    int textSize=60;
    int select=-1;
    int selectWidth=0;
    List<Integer> colors=new ArrayList<>();
    private ItemClick itemClick;

    public MyView(Context context) {
        this(context,null);
        init();
    }


    public MyView(Context context,  AttributeSet attrs) {
        super(context,attrs);
        this.context=context;
        init();
    }

    private void testData(){
        data.add(new Data(0.1F,"one"));
        data.add(new Data(0.1F,"two"));
        data.add(new Data(0.1F,"three"));
        data.add(new Data(0.2F,"four"));
        data.add(new Data(0.1F,"five"));
        data.add(new Data(0.1F,"six"));
        data.add(new Data(0.3F,"seven"));


    }

    private void init(){

       // testData();


        paint=new Paint();
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(strokeWidth);
        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);

        linePaint=new Paint();
        linePaint.setColor(Color.BLACK);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(lineWidth);

        textPaint=new Paint();
        textPaint.setColor(Color.BLACK);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setTextSize(textSize);

        colors.add(Color.RED);
        colors.add(Color.BLACK);
        colors.add(Color.GREEN);
        colors.add(Color.BLUE);
        colors.add(Color.YELLOW);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
/*        if(w==h){
        }else{
            if(w>h){
                w=h;
            }else{
                h=w;
            }
        }*/
        mWidth=w;
        mHeight=h;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int centerX=mWidth/2;
        int centerY=mHeight/2;
        float angle=0;
        int i=0;
        for (Data d :  data){
            Path path=new Path();
            d.setAngle(angle);
            Log.v("zzw","angle "+angle);
            float lineAngle=angle+180*d.getWeight();
            double radians = Math.toRadians(lineAngle);
            double x=0,y=0;
            linePaint.setColor(colors.get(i));
            textPaint.setColor(colors.get(i));

            if(lineAngle<90){
                x=centerX+circleWidth*Math.cos(radians);
                y=centerY+circleWidth*Math.sin(radians);
                canvas.drawLine((float) x,(float)y,(float)x+slantLineLenght,(float)y+slantLineLenght,linePaint);
                x=x+slantLineLenght-lineOffSet;
                y=y+slantLineLenght;
                canvas.drawLine((float) x,(float)y,(float)x+straightLineLenght,(float)y,linePaint);
                float l= textPaint.measureText(d.getDescribe());
                canvas.drawText(d.getDescribe(),(float) x+straightLineLenght-l,(float)y+textSize-lineWidth,textPaint);

            }else if(lineAngle>=90&&lineAngle<180){
                x=centerX+circleWidth*Math.cos(radians);
                y=centerY+circleWidth*Math.sin(radians);
                canvas.drawLine((float) x,(float)y,(float)x-slantLineLenght,(float)y+slantLineLenght,linePaint);
                x=x-slantLineLenght+lineOffSet;
                y=y+slantLineLenght;
                canvas.drawLine((float) x,(float)y,(float)x-straightLineLenght,(float)y,linePaint);
                canvas.drawText(d.getDescribe(),(float)x-straightLineLenght,(float)y+textSize-lineWidth,textPaint);

            }else if(lineAngle>=180&&lineAngle<270){
                x=centerX+circleWidth*Math.cos(radians);
                y=centerY+circleWidth*Math.sin(radians);
                canvas.drawLine((float) x,(float)y,(float)x-slantLineLenght,(float)y-slantLineLenght,linePaint);
                x=x-slantLineLenght+lineOffSet;
                y=y-slantLineLenght;
                canvas.drawLine((float) x,(float)y,(float)x-straightLineLenght,(float)y,linePaint);
                canvas.drawText(d.getDescribe(),(float)x-straightLineLenght,(float)y-lineWidth,textPaint);

            }else if(lineAngle>=270&&lineAngle<360){
                x=centerX+circleWidth*Math.cos(radians);
                y=centerY+circleWidth*Math.sin(radians);
                canvas.drawLine((float) x,(float)y,(float)x+slantLineLenght,(float)y-slantLineLenght,linePaint);
                x=x+slantLineLenght-lineOffSet;
                y=y-slantLineLenght;
                canvas.drawLine((float) x,(float)y,(float)x+straightLineLenght,(float)y,linePaint);
                float l= textPaint.measureText(d.getDescribe());
                canvas.drawText(d.getDescribe(),(float)x+straightLineLenght-l,(float)y-lineWidth,textPaint);
            }


            RectF rectF=new RectF(centerX-circleWidth,centerY-circleWidth,centerX+circleWidth,centerY+circleWidth);
            path.addArc(rectF,angle,360*d.getWeight());
            if(select==i){
                paint.setStrokeWidth(selectWidth);
            }else {

                paint.setStrokeWidth(strokeWidth);
            }

            angle=angle+360*d.getWeight();
            paint.setColor(colors.get(i));
            i++;
            if(i+1>=colors.size()){
                i=0;
            }
            canvas.drawPath(path,paint);



        }





    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int centerX=mWidth/2;
        int centerY=mHeight/2;
        float x= event.getX();
        float y=event.getY();

        double angle;
        if(y>=centerY&&x>=centerX){
            angle= Math.toDegrees(Math.atan((y-centerY)/(x-centerX)));
        }else if(y>=centerY&&x<=centerX){
            angle= 180+Math.toDegrees(Math.atan((y-centerY)/(x-centerX)));
        }else if(y<=centerY&&x<=centerX){
            angle= 180+Math.toDegrees(Math.atan((y-centerY)/(x-centerX)));
        }else{
            angle= 360+Math.toDegrees(Math.atan((y-centerY)/(x-centerX)));
        }

        for(int i=0;i<=data.size()-1;i++){
            if(i==data.size()-1){
                if(data.get(i).getAngle()<=angle&&360>angle){
                    select=i;
                    ValueAnimator animator= ValueAnimator.ofInt(strokeWidth,strokeWidth*2);
                    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            selectWidth= (int) animation.getAnimatedValue();
                            invalidate();

                        }
                    });
                    animator.setDuration(500);
                    animator.start();
                    if(itemClick!=null){
                        itemClick.click(i);



                    }
                    Log.v("zzw","click at "+i);
                    break;
                }
            }else{
                if(data.get(i).getAngle()<=angle&&data.get(i+1).getAngle()>angle){
                    select=i;
                    ValueAnimator animator= ValueAnimator.ofInt(strokeWidth,strokeWidth*2);
                    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            selectWidth= (int) animation.getAnimatedValue();
                            invalidate();

                        }
                    });
                    animator.setDuration(500);
                    animator.start();
                    if(itemClick!=null){

                        itemClick.click(i);

                    }
                    Log.v("zzw","click at "+i);
                    break;
                }
            }

        }

        Log.v("zzw",angle+"");

        return super.onTouchEvent(event);
    }

    public static class Data{
        private float weight;
        private String describe;
        private float angle;

        public Data(float f,String s){
            weight=f;
            describe=s;
        }

        public float getWeight() {
            return weight;
        }

        public void setWeight(float weight) {
            this.weight = weight;
        }

        public String getDescribe() {
            return describe;
        }

        public void setDescribe(String describe) {
            this.describe = describe;
        }

        public float getAngle() {
            return angle;
        }

        public void setAngle(float angle) {
            this.angle = angle;
        }
    }

    public interface ItemClick{
        public void click(int p);
    }

    public ItemClick getItemClick() {
        return itemClick;
    }

    public void setItemClick(ItemClick itemClick) {
        this.itemClick = itemClick;
    }

    public void refreshData(List<Data> list){
        data.clear();
        data.addAll(list);
        invalidate();
    }


}

 

参考文章:

http://www.gcssloop.com/customview/CustomViewIndex/

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值