PathMeasure

PathMeasure

PathMeasure是一个用来测量Path的类,主要有以下方法:

构造方法

方法名释义
PathMeasure()创建一个空的PathMeasure
PathMeasure(Path path, boolean forceClosed)创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)

公共方法

返回值方法名释义
voidsetPath(Path path, boolean forceClosed)关联一个Path
booleanisClosed()是否闭合
floatgetLength()获取Path的长度
booleannextContour()跳转到下一个轮廓
booleangetSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)截取片段
booleangetPosTan(float distance, float[] pos, float[] tan)获取指定长度的位置坐标及该点切线值tangle
booleangetMatrix(float distance, Matrix matrix, int flags)获取指定长度的位置坐标及该点Matrix(矩阵)

1.构造函数

无参构造函数:

PathMeasure ()

用这个构造函数可创建一个空的 PathMeasure,但是使用之前需要先调用 setPath 方法来与 Path 进行关联。被关联的 Path 必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。

有参构造函数:

PathMeasure (Path path, boolean forceClosed)

1.用这个构造函数是创建一个 PathMeasure 并关联一个 Path, 其实和创建一个空的 PathMeasure 后调用 setPath 进行关联效果是一样的,同样,被关联的 Path 也必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。

2.该方法有两个参数,第一个参数自然就是被关联的 Path 了,第二个参数是用来确保 Path 闭合,如果设置为 true, 则不论之前Path是否闭合,都会自动闭合该 Path(如果Path可以闭合的话)。

在这里有两点需要明确:

  1. 不论 forceClosed 设置为何种状态(true 或者 false), 都不会影响原有Path的状态,即 Path 与 PathMeasure 关联之后,之前的的 Path 不会有任何改变。
  2. forceClosed 的设置状态可能会影响测量结果,如果 Path 未闭合但在与 PathMeasure 关联的时候设置 forceClosed 为 true 时,测量结果可能会比 Path 实际长度稍长一点,获取到到是该 Path 闭合时的状态。

setPath、isClosed 和 getLength

  1. setPath 是 PathMeasure 与 Path 关联的重要方法,效果和 构造函数 中两个参数的作用是一样的。
  2. isClosed 用于判断 Path 是否闭合,但是如果你在关联 Path 的时候设置 forceClosed 为 true 的话,这个方法的返回值则一定为true。
  3. getLength 用于获取 Path 的总长度,在之前的测试中已经用过了。

getSegment

getSegment 用于获取Path的一个片段,方法如下:

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

方法各个参数释义:

参数作用备注
返回值(boolean)判断截取是否成功true 表示截取成功,结果存入dst中,false 截取失败,不会改变dst中内容
startD开始截取位置距离 Path 起点的长度取值范围: 0 <= startD < stopD <= Path总长度
stopD结束截取位置距离 Path 起点的长度取值范围: 0 <= startD < stopD <= Path总长度
dst截取的 Path 将会添加到 dst 中注意: 是添加,而不是替换
startWithMoveTo起始点是否使用 moveTo用于保证截取的 Path 第一个点位置不变

如果 startD、stopD 的数值不在取值范围 [0, getLength] 内,或者 startD == stopD 则返回值为 false,不会改变 dst 内容。
如果在安卓4.4或者之前的版本,在默认开启硬件加速的情况下,更改 dst 的内容后可能绘制会出现问题,请关闭硬件加速或者给 dst 添加一个单个操作,例如: dst.rLineTo(0, 0)

可以用以下规则来判断 startWithMoveTo 的取值:

取值主要功用
true保证截取得到的 Path 片段不会发生形变
false保证存储截取片段的 Path(dst) 的连续性

nextContour

我们知道 Path 可以由多条曲线构成,但不论是 getLength , getgetSegment 或者是其它方法,都只会在其中第一条线段上运行,而这个 nextContour 就是用于跳转到下一条曲线到方法,如果跳转成功,则返回 true, 如果跳转失败,则返回 false。

getPosTan

这个方法是用于得到路径上某一长度的位置以及该位置的正切值:

boolean getPosTan (float distance, float[] pos, float[] tan)

方法各个参数释义:

参数作用备注
返回值(boolean)判断获取是否成功true表示成功,数据会存入 pos 和 tan 中,false表示失败,pos 和 tan 不会改变
distance距离 Path 起点的长度取值范围: 0 <= distance <= getLength
pos该点的坐标值坐标值: (x==[0], y==[1])
tan该点的正切值正切值: (x1==[0], y1==[1])

通过 tan 得值计算出图片旋转的角度,tan 是 tangent 的缩写,即中学中常见的正切, 其中tan0是邻边边长,tan1是对边边长,而Math中 atan2 方法是根据正切是数值计算出该角度的大小,得到的单位是弧度,所以上面又将弧度转为了角度。
atan2(弧度) = L(弧长)/r(半径)= atan2(y1, x1)
L = nMath.PI*R/180
=>n=180*L/(R*Math.PI)
=>n=atan2(y1,x1)*180/Math.PI

比如:

boolean posTan = mPathMeasure.getPosTan(length*faction,pos,tan);
if(posTan){
    //将tan值通过反正切函数得到对应的弧度,在转化成对应的角度度数
    float degrees = (float) (Math.atan2(tan[1],tan[0])*180f / Math.PI);
    mMatrix.postRotate(degrees, mBitMap.getWidth()/2, mBitMap.getHeight() / 2);
    mMatrix.postTranslate(pos[0]- mBitMap.getWidth() / 2,pos[1] - mBitMap.getHeight());
    canvas.drawBitmap(mBitMap,mMatrix,mPaint);

getMatrix

这个方法是用于得到路径上某一长度的位置以及该位置的正切值的矩阵:

boolean getMatrix (float distance, Matrix matrix, int flags)

方法各个参数释义:

参数作用备注
返回值(boolean)判断获取是否成功true表示成功,数据会存入matrix中,false 失败,matrix内容不会改变
distance距离 Path 起点的长度取值范围: 0 <= distance <= getLength
matrix根据 falgs 封装好的matrix会根据 flags 的设置而存入不同的内容
flags规定哪些内容会存入到matrix中可选POSITION_MATRIX_FLAG(位置) ANGENT_MATRIX_FLAG(正切)

例子

这里写图片描述

public class LoadingView1 extends View {
    private Path mPath;
    private Paint mPaint;
    private PathMeasure mPathMeasure;
    private float mAnimatorValue;
    private Path mDst;
    private float mLength;

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

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

    }
    public LoadingView1(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        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();

        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                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();
        mDst.lineTo(0,0);

        float stop = mLength * mAnimatorValue;
        float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));

        mPathMeasure.getSegment(start, stop, mDst, true);

        canvas.drawPath(mDst, mPaint);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值