美文网首页AndroidView
Android动画 - PathMeasure打造不一样的动画

Android动画 - PathMeasure打造不一样的动画

作者: xzmmhello | 来源:发表于2020-10-28 10:45 被阅读0次

    Android动画 - PathMeasure打造不一样的动画

    PathMeasures是什么

    顾名思义,PathMeasure是一个用来测量Path的类

    构造函数

    构造函数 方法描述
    PathMeasure() 创建一个空的PathMeasure对象。
    PathMeasure(Path path, boolean forceClosed) 创建与指定路径对象(已经创建并指定)关联的PathMeasure对象。

    公共方法

    返回值 方法名称
    float getLength()
    boolean getMatrix(float distance, Matrix matrix, int flags)
    boolean getPosTan(float distance, float[] pos, float[] tan)
    boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
    boolean isClosed()
    boolean nextContour()
    void setPath(Path path, boolean forceClosed)

    接下来分别介绍下以上的方法


    1.构造函数

    无参构造函数:
    PathMeasure()
    

    创建一个空的PathMeasure,要使用它来测量路径长度,或查找路径的位置和切线,需要调用setPath。一旦路径与测量对象相关联,Path进行了更改,需要重新调用setPath方法。

    有参构造函数
    PathMeasure(Path path, boolean forceClosed)
    

    创建与指定路径对象关联的PathMeasure对象。现在,测量对象可以返回路径的长度以及路径上任何位置的位置和切线。同上,一旦路径与测量对象相关联,Path进行了更改,需要重新调用setPath方法。
    forceClosed:如果为true,该路径也将被视为“闭合”。

    forceClosed不会影响Path本身的状态。但是会影响测量结果。

    下面我们举个例子:

        canvas.translate(mWidth/2,mHeight/2);
    
        Path path = new Path();
        path.lineTo(0,200);
        path.lineTo(200,200);
        path.lineTo(200,0);
        PathMeasure measure1 = new PathMeasure(path,false);
        PathMeasure measure2 = new PathMeasure(path,true);
    
        Log.e("TAG", "forceClosed=false---->"+measure1.getLength());
        Log.e("TAG", "forceClosed=true----->"+measure2.getLength());
        canvas.drawPath(path,mDeafultPaint);
    

    log如下:

    E/TAG: forceClosed=false---->600.0
    E/TAG: forceClosed=true----->800.0
    

    绘制的效果如下:


    4041603852675_.pic_thumb.jpg

    2.公共方法

    getLength

    返回当前Path的总长度;如果没有路径与此度量对象关联,则返回0。

    isClosed

    如果当前Path为close(),则返回true。

    setPath

    Path与PathMeasure进行关联。
    主要讲一下以下几个方法:

    nextContour

    public boolean nextContour()
    

    获取在路径中下一个轮廓,如果有下一个轮廓,则返回true,且PathMeasure切至下一个轮廓的数据;如果没有下一个轮廓则返回false。
    我的理解一次moveTo增加一个轮廓。

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

    给定起点和终点的距离,请返回中间的路段。如果段的长度为零,则返回false,否则返回true。startD和stopD固定取值范围(0,getLength())。如果startD> = stopD,则返回false(并保持dst不变)。如果startWithMoveTo为true,则以moveTo开头。

    参数 作用
    startD 开始截取的位置距离Path起点的距离
    stopD 结束截取的位置距离Path起点的距离
    dst 截取的Path会添加到dst中
    startWithMoveTo 起点是否启用moveTo

    startD 和 stopD 的取值范围 0 <= startD < stopD <= getLength
    startWithMoveTo: 截取的片段的第一个点是否保持不变;
    设置为true:保持截取的片段不变,添加至dst路径中;
    设置为false:会将截取的片段的起始点移至dst路径中的最后一个点,让dst路径保持连续

    举个例子:startWithMoveTo 为flase

    canvas.translate(width/2,height/2);
    Path mPath = new Path();
    Path mDst = new Path();
    PathMeasure mPathMeasure = new PathMeasure();
    // 顺时针画 半径为400px的圆
    mPath.addCircle(0,0, 400, Path.Direction.CW);
    mPathMeasure.setPath(mPath, false);
    
    // 画直线
    mDst.moveTo(110, 0);
    mDst.lineTo(200, 300);
    
    // 截取 0.25 到 0.5 距离的圆弧放置dst中
    mPathMeasure.getSegment(mPathMeasure.getLength() * 0.25f,
                    mPathMeasure.getLength() * 0.5f,
                    mDst,
                    false);
    
    canvas.drawPath(mDst, paint);
    

    效果图如下:


    4011603795757_.pic_thumb.jpg

    startWithMoveTo 为true
    效果图如下:


    4021603795817_.pic_thumb.jpg
    getPosTan
    public boolean getPosTan(float distance, float pos[], float tan[]) 
    
    参数 作用
    distance 即需要的测量点与当前path起始位置的距离
    pos 测量点的坐标,pos[0]为x坐标,pos[1]为y坐标
    tan 测量点的正余弦值,tan[0]为cos,即余弦值或称为单位圆的x坐标;tan[1]为sin,即正弦值或称为单位圆的y坐标;

    distance 取值范围:0<=distance<=getLength()
    A(x,y)原点为O,cos = OA/OB,sin = OA/AB

    getMatrix

    public boolean getMatrix(float distance, Matrix matrix, int flags)
    
    参数 作用
    distance 即需要的测量点与当前path起始位置的距离
    matrix 根据 falgs 封装好的matrix
    flags 规定哪些内容会存入到matrix中

    flags 有POSITION_MATRIX_FLAG(位置) 和 ANGENT_MATRIX_FLAG(正切)两种
    其实这个方法就相当于getPosTan的封装 matrix 的过程由 getMatrix 替我们做了,我们可以直接得到一个封装好到 matrix。

    实战

    加载动画(一)

    效果图

    LoadingCircleView.gif

    主要利用PathMeasure的getSegment方法来截取路径,绘制该动画

    思路

    1.先勾勒出一个顺时针的空心圆,然后生成pathMeasure对象

    // 勾勒空心圆
    path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
    // 生成pathMeasure对象
    pathMeasure.setPath(path, true);
    

    2.截取的开始值和结束值

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

    mAnimatorValue 的取值为(0,1) ,当mAnimatorValue为0或1时,两个值相等。

    3.截取路径后绘制路径

    pathMeasure.getSegment(start, stop, dst, true);
    canvas.drawPath(dst, paint);
    

    完整代码地址:
    有用记得点颗小星星


    加载动画化(二)

    效果图

    LoadingArrowView.gif

    思路

    主要利用getPosTan 获取测量点的坐标和正余弦值,控制箭头的方法和位置
    1.先勾勒出一个顺时针的空心圆,然后生成pathMeasure对象

    // 勾勒空心圆
    path.addCircle(width / 2, height / 2, radius, Path.Direction.CW);
    // 生成pathMeasure对象
    pathMeasure.setPath(path, true);
    

    2.获取绘制点的测量坐标和正余弦值,根据tan[0],tan[1]来计算箭头旋转的角度。

    measure.getPosTan(measure.getLength() * mAnimatorValue, pos, tan);
    float angle = (float) (Math.atan2(tan[1], tan[0]) * 180 / Math.PI);
    

    mAnimatorValue 的取值为(0,1) ,当mAnimatorValue为0或1时,两个值相等。
    angle计算方式自行查找,数学知识。

    3.用Matrix对bitmap进行旋转和平移

    mMatrix.postRotate(angle,mBitmap.getWidth()/2,mBitmap.getHeight()/2);
    mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2,pos[1] - mBitmap.getHeight() / 2);
    

    4.绘制bitmap

    canvas.drawBitmap(mBitmap,mMatrix,mPaint);
    

    完整代码地址:
    有用记得点颗小星星


    往期文章地址

    Android动画 - 仿花束直播加载动画
    Android动画 - 仿58同城加载动画
    Android动画 - 仿抖音加载动画

    相关文章

      网友评论

        本文标题:Android动画 - PathMeasure打造不一样的动画

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