美文网首页
Android 自定义View 之 Path PathMeasu

Android 自定义View 之 Path PathMeasu

作者: 嘉伦哥 | 来源:发表于2020-09-07 19:41 被阅读0次

    最近项目要求做一个进度条,头部有一个龟头小圆,如下:

    微信图片_20200907184109.png

    拿到图第一时间就是对整个图片进行技术拆分,由内到外可分为5个部分:


    456.png

    1.绘制实心圆

    Paint pain=new Paint;
    pain.setStyle(Paint.Style.FILL);
    addCircle(float x, float y, float radius, @NonNull Direction dir)
    

    2.绘制二阶贝塞尔曲线

    quadTo(float x1, float y1, float x2, float y2)
    

    3.根据4的轨迹通过PathMeasure 截取 片段

    getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
    

    4.绘制空心圆

    Paint pain=new Paint;
    pain.setStyle(Paint.Style.STROKE);
    addCircle(float x, float y, float radius, @NonNull Direction dir)
    

    5.一个外圈空心圆包裹一个内圈实心圆

    pathMeasure.getPosTan
    

    1和2部分下一篇博客加上,因为涉及贝塞尔曲线
    好了, 来看看3-5核心代码。

        private void initView(Context context, AttributeSet attrs) {
            //内圈画笔
            insidePaint = new Paint();
            insidePaint.setAntiAlias(true);//去锯齿
            insidePaint.setStyle(Paint.Style.STROKE);
            insidePaint.setStrokeWidth(insideStrokeWidth);
            insidePaint.setColor(Color.WHITE);
    
    
            //外圈画笔
            outsidePaint = new Paint();
            outsidePaint.setAntiAlias(true);//去锯齿
            outsidePaint.setStyle(Paint.Style.STROKE);
            outsidePaint.setStrokeWidth(outSideStrokeWidth);
            outsidePaint.setColor(Color.WHITE);
    
    
            //小龟头空心圆圈画笔
            smallPaint = new Paint();
            smallPaint.setAntiAlias(true);
            smallPaint.setStyle(Paint.Style.STROKE);
            smallPaint.setStrokeWidth(smallStrokeWidth);
            smallPaint.setColor(Color.WHITE);
    
            //小龟头内圈实体圆圈画笔
            smallInsidePaint = new Paint();
            smallInsidePaint.setAntiAlias(false);
            smallInsidePaint.setStyle(Paint.Style.FILL);
            smallInsidePaint.setColor(getResources().getColor(R.color.color_5FBBEB));
        }
    

    大致是初始化了4个画笔,从上到下分别负责:4-3-5

    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            outSidePath = new Path();
            insidePath = new Path();
    
            insidePath.addCircle((w) / 2f + insideStrokeWidth
                    , (h) / 2f + insideStrokeWidth
                    , (h) / 2f - 2 * insideStrokeWidth - outSideStrokeWidth
                    , Path.Direction.CW);
    
    
         
            pathMeasure.setPath(insidePath, true);
        }
    

    在 sizeChanged阶段 初始化 外圈 内圈 的路径Path,并且初始化内圈半径参数

    核心部分

       @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            outSidePath.reset();
            float length = pathMeasure.getLength();
            canvas.drawPath(insidePath, insidePaint);
            float startD = 0;
            float stopD = (Math.abs(progress)) / 100f * length;
            pathMeasure.getSegment(startD, stopD, outSidePath, true);
    
            if (progress != 1) {
                canvas.drawPath(outSidePath, outsidePaint);
            }
    
            pathMeasure.getPosTan(stopD + 2 + outSideStrokeWidth, pos, tan);
    
            Log.d(TAG, "THE POS IS:" + pos[0] + "tan:" + tan[0] + "...stopD:" + stopD);
            if (progress != 100 && progress != 1) {
                //绘制龟头外圈
                canvas.drawCircle(pos[0], pos[1], outSideRadius, smallPaint);
                //绘制龟头外圈
                canvas.drawCircle(pos[0], pos[1], (outSideRadius - smallStrokeWidth / 2), smallInsidePaint);
            }
        }
    

    绘制阶段大部分都是计算:有截取片段的开始startD 、stopD和 求曲线路径当前正切坐标值getPosTan
    通过外部传进来的Progress 进度控制 截取长度,进而达到类似progress 一直在动的效果。
    最后得到初步效果如下:

    ps:下方黑色的动效为:[Android 自定义View 之 Path PathMeasure (一)]

    VID_20200907183216.gif

    刚开始写博客,格式不是很好,凑合着看吧,有需要的可以私信 ~

    相关文章

      网友评论

          本文标题:Android 自定义View 之 Path PathMeasu

          本文链接:https://www.haomeiwen.com/subject/wyilektx.html