读《PathMeasure之迷径追踪》相关笔记

所阅读博客地址:PathMeasure之迷径追踪,下文简称为《迷径》
另外参考博客:安卓自定义View进阶-PathMeasure使用DashPathEffect绘制一条动画曲线


1、

在《迷径》中的第一个例子,是实现下图的效果:
这里写图片描述
开始对其中的部分代码不太理解,后来想了一会儿之后想通了,以此记录:

public class PathPainter extends View {
    ...

    public PathPainter(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPathMeasure = new PathMeasure();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPath = new Path();
        mPath.addCircle(400, 400, 100, Path.Direction.CW);
        mPathMeasure.setPath(mPath, true);
        //获取路径的长度,这里即圆的周长
        mLength = mPathMeasure.getLength();
        mDst = new Path();

        //ofLoat() 是从 0 - 1,用来进度
        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //例如,当 mAnimatorValue 值为 0.1f 时,就表示整个圆周长的 10% 位置处(相对于圆的起点位置)
                mAnimatorValue = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setDuration(2000);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mDst.reset();
        // 硬件加速的BUG
        mDst.lineTo(0,0);
        float stop = mLength * mAnimatorValue;
        //虽然被截取的 Path 片段是被添加到 dst 中,而不是每次被覆盖,
        // 但是由于在本次Demo中总是不断截取同一个圆的片段(且片段的长度越来越大直到整个为整个圆的路径),
        // 因此每次添加的片段路径是周期性的,且在前面利用 reset() 清空了上一次的数据,跟覆盖的效果一样
        mPathMeasure.getSegment(0, stop, mDst, true);
        canvas.drawPath(mDst, mPaint);
    }
}

2、

然后是实现下面的动画
这里写图片描述
就只需要将原来的绘制的起点改为如下

float stop = mLength * mAnimatorValue;
float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));
mPathMeasure.getSegment(start, stop, mDst, true);

其中的关键点就是那个公式,简化之后为:

mLength * (mAnimatorValue - 0.5 + |mAnimatorValue - 0.5|)

当 mAnimatorValue <= 0.5, 实际上 start = 0;
当 mAnimatorValue > 0.5, start 为 mLength * (2 * mAnimatorValue -1) ,范围为 mLength * (0 , 1] ;

所以在半圈之前,效果跟第一个动图的效果是一样的,但是超过半圈之后,绘制的路径的起点会快速向终点靠近,以致于所绘制的路径越来越短,最后起始点重合。


3、DashPathEffect

DashPathEffect作用是将Path的线段虚线化。

DashPathEffect (float[] intervals, float phase)

对于上面的两个参数,第一个是间隔数组,且数组长度需要 >= 2,长度最后为偶数的,否则最后一个奇数位的会失效。****第二个参数表示偏移长度。接下来就用图片来具体解释一下。

new DashPathEffect(new float[]{150,150}, 0); 为例,其中最左边的第一根辅助线的横坐标为第 100,最后一根辅助线的横坐标为第 850(每隔 50 一根辅助线),对应的线段也是从 100 画到 850,在使用了 DashPathEffect 之后就是如下结果:
这里写图片描述
而当把 phase 设置为 50 的时候,即 new DashPathEffect(new float[]{150,150}, 50);,其余条件不变,结果就变成如下:
这里写图片描述
而当把 phase 设置为 100 的时候,,结果就变成如下:
这里写图片描述
然后按照下面的想法想,可能会跟实际的不同,但是按照下面的那样想会容易一点,便于理解第4 节效果图的实现原理:

根据上面的那些图,就可以很直观的展示出参数 phase 的作用,即在从起点画了长度为 new float[]{X,Y} 中 X 的长后,往左偏移回 phase 值的长度,然后开始绘制 Y 长度的空白,再绘制 X 长度的线段,再绘制 Y 长度的空白,以及往复,直到到达终点,之后就不会再绘制了,即使此时空白段还没有开始绘制或者还没有绘制完,一定要记住这里,不然在第 4 节那儿可能会被坑,以为空白线段一定要绘制设定的长度才算

这这个例子中,先是从第一根辅助线开始到第四根辅助线画出一条线段,即 150 长的线段,但是因为 phase = 100,所以要偏移回(即回退) 100 的长度,即从第四根辅助线退回到第二根,在回退的过程中会抹去已经绘制的线段(用形象的说法就是用橡皮擦擦去),然后从第二根辅助线开始画长度 150 长的空白,再画 150 的线段,如此往复下去。(这样想,下面那一节展示的那个效果图就能想清楚为什么会是那样的效果了)

这里再附上 new DashPathEffect(new float[]{150,150}, 200); 的结果图,其余条件按上述所示:
这里写图片描述
这里就比较特殊了,但本质思想还是没变,先是从第一个辅助线(还是最左边第一根红色的)开始到第四根辅助线画出一条线段,即 150 长的线段,但是因为 phase = 200,所以要偏移回(即回退) 200 的长度,即使回退到了起点也不会停止,直到回退到那条蓝色辅助线(为了体现效果额外加的)那儿为止,然后从该线开始画长度 150 长的空白,再画 150 的线段,如此往复下去。

注意,当 phase 为负数时,则需要变换一下思想。
phase = -50图 1
phase = -200图 2
即虽然实际上线段整体是从左往右画的(即从 100 画到 850),当 phase 为负数时,需要想作是从右画到左(即从 850 到 100),然后以上面图 2 为例,先是从第十六根(即最右边到)红色辅助线开始到第十三根辅助线画出一条线段,即 150 长的线段,但是因为 phase = -200,所以要偏移回(即回退) 200 的长度,即从第十三根辅助线退回到最右边的蓝色辅助线(即偏移回 200),然后从蓝色辅助线开始向左画长度 150 长的空白,再画 150 的线段,如此往复下去,直到第一根辅助线。


4、

然后《迷径》中如下的效果图:
这里写图片描述

首先需要明确的是,三角的画的方向本身就是从左上角那个点开始,然后往下,再拐角往右上,再回到起点。
然后就是利用 ValueAnimator.ofFloat(1, 0),加上下面的核心代码:

fraction = (float) valueAnimator.getAnimatedValue();
mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
mPaint.setPathEffect(mEffect);

之后不断重绘就行了。
假设三角形周长为600,则 phase 的值就是从 600 减到 0 的,然后利用第 3 点的解释说明去在脑中模拟或者自己用比试试,就能明白这个效果图的原理了。
或者看下面我自己录制的 GIF 图(请忽略做工),其中黑色线段代表实际绘制的线段,白色线段代表回退的效果(假设回退了500,即 phase = fraction * length = 500),紫色线段代表实际空白的绘制。
这里写图片描述

或者是
ValueAnimator.ofFloat(0, 1) + mEffect = new DashPathEffect(new float[]{length, length}, length - fraction * length);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值