安卓开发之使用PathMeasure自定义加载动画控件

来源:互联网 发布:人工智能用go语言开发 编辑:程序博客网 时间:2024/05/21 18:46

先上效果图:

这里写图片描述

一、PathMeasure

在绘制画布时,我们通常会使用Path对象来勾勒出绘制的路径,而PathMeasure可以让我们得到路径上的一些信息,比如获取路径上点的坐标,截取路径上的某一段小路径等。。

它主要有既个方法:

  • setPath(Path path, boolean forceClosed);

    与一个Path对象绑定,forceClose为true时,不管关联的Path是否是闭合的,都会被闭合。

  • getLength()

    获取路径的长度

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

    distance 为一个 0 - getLength() 之间的值,根据这个距离值计算出当前点的xy坐标和正切值封装到 pos和tan当中;

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

    判断截取路径成功时返回true;

    startD为开始截取位置距离 Path 起点的长度
    stopD 结束截取位置距离 Path 起点的长度
    取值范围: 0 <= startD < stopD <= Path总长度getLength(),超过范围截取不成功

    截取的 Path 将会添加到 dst 中

    startWithMoveTo 起始点是否使用 moveTo,用于保证截取的 Path 第一个点位置不变(一般为true)

    在默认开启硬件加速的情况下,更改 dst 的内容后可能绘制会出现问题,可以给 dst 添加一个操作:dst.lineTo(0, 0)

二、自定义动画控件

大概思路就是:

创建一个勾勒空心圆的Path对象
再根据上面的Path对象创建PathMeasure对象
最后再通过属性动画不断动态获取startD和stopD的值,并更新View

public class LoadingCircleView extends View {    private Path path;    private PathMeasure pathMeasure;    private Path dst; // 被截取的路径    private Paint paint; // 画笔    // View的宽高    private int height;    private int width;    private float radius; // 空心圆的半径    private float mLength; // path路径的长度    ValueAnimator valueAnimator; // 属性动画    private float mAnimatorValue; // 属性动画返回的百分比    private float stop; // 截取路径时的stopD值    private float start; // 截取路径时的startD值    public LoadingCircleView(Context context) {        super(context);        init(); // 初始化    }    public LoadingCircleView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public LoadingCircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public LoadingCircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init();    }    private void init() {        radius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,21,getContext().getResources().getDisplayMetrics()); // 初始化半径        path = new Path();        dst = new Path();        paint = new Paint();        pathMeasure = new PathMeasure();        // 设置画笔属性        paint.setAntiAlias(true);        paint.setColor(0xbfe46d32);        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeCap(Paint.Cap.ROUND);        paint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,3.5f,getContext().getResources().getDisplayMetrics()));    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        width = w;        height = h;        // 勾勒空心圆        path.reset();        path.addCircle(width/2,height/2,radius, Path.Direction.CW);        // 生成pathMeasure对象        pathMeasure.setPath(path,true);        // 获取path的长度        mLength = pathMeasure.getLength();        // 通过属性动画取得百分比值,并更新View        valueAnimator = ValueAnimator.ofFloat(0,1);        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                // 获取动画进行的百分比                mAnimatorValue = (float) animation.getAnimatedValue();                postInvalidate(); // 更新界面            }        });        // 设置动画的属性        valueAnimator.setDuration(2100);        valueAnimator.setRepeatCount(1000);        valueAnimator.setRepeatMode(ValueAnimator.RESTART);        valueAnimator.start();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        // 只对EXACTLY的条件的宽高处理        setMeasuredDimension(Math.min(widthSize,heightSize),Math.min(widthSize,heightSize));    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        // 为加强动画效果,每次对画布旋转不同角度        canvas.rotate(360.0f*mAnimatorValue-45.0f,width/2,height/2);        // 初始化截取的路径        dst.reset();        dst.lineTo(0,0); // 消除硬件加速的影响        // 更新截取的开始值和结束值:当mAnimatorValue为0或1时,两个值相等        stop = mAnimatorValue*mLength;        start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));        // 截取路径后,并绘制路径        pathMeasure.getSegment(start, stop, dst, true);        canvas.drawPath(dst,paint);    }}

参考:

PathMeasure之迷径追踪

0 0
原创粉丝点击