路径动画

引言

路径动画,顾名思义,是沿着设定好的路径进行动画的展示。

示例代码

先看代码

public class PathView extends View {
private Path mPath;
private Paint mPaint;
private Matrix mMatrix;
private PathMeasure mPathMeasure;

private Bitmap mBitmapHand;

private float mLength;
private float mAnimatorValue;
private float mCurrentPos[], mCurrentTan[];
private float mViewWidth, mViewHeight;

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

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

public PathView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = 2;
    mBitmapHand = BitmapFactory.decodeResource(getResources(), R.drawable.icon_rubber_guide_hand, opts);

    mMatrix = new Matrix();

    mCurrentPos = new float[2];
    mCurrentTan = new float[2];

    mPaint = new Paint();
    mPaint.setColor(Color.CYAN);
    mPaint.setStrokeWidth(1);
    mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.STROKE);

    mPath = new Path();
    mPath.moveTo(100, 100);
    mPath.lineTo(400, 100);
    mPath.lineTo(400, 400);
    mPath.lineTo(100, 400);

    mPathMeasure = new PathMeasure();
    mPathMeasure.setPath(mPath, true);//设置为true自动闭合形成一个矩形
    mLength = mPathMeasure.getLength();

    ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,1);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mAnimatorValue=animation.getAnimatedFraction();
            postInvalidate();
        }
    });
    valueAnimator.setDuration(2000L);
    valueAnimator.setRepeatCount(3);
    valueAnimator.start();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    mViewWidth = getWidth();
    mViewHeight = getHeight();
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.translate(mViewWidth / 2, mViewHeight / 2);      // 平移坐标系

//        Path path = new Path();                                 // 创建 Path
//        path.addCircle(0, 0, 200, Path.Direction.CW);           // 添加一个顺时针圆形,CCW为逆时针
//        mAnimatorValue += 0.005;                                  // 计算当前的位置在总长度上的比例[0,1]
//        if (mAnimatorValue >= 1) {
//            mAnimatorValue = 0;
//        }

    mPathMeasure.getPosTan(mLength * mAnimatorValue, mCurrentPos, mCurrentTan);// 获取当前位置的坐标以及趋势

    mMatrix.reset(); // 重置Matrix
    float degrees = (float) (Math.atan2(mCurrentTan[1], mCurrentTan[0]) * 180.0 / Math.PI); // 计算图片旋转角度

    mMatrix.postRotate(degrees, mBitmapHand.getWidth() / 2, mBitmapHand.getHeight() / 2);
    mMatrix.postTranslate(mCurrentPos[0] - mBitmapHand.getWidth() / 2, mCurrentPos[1] - mBitmapHand.getHeight() / 2);
    canvas.drawPath(mPath, mPaint); // 绘制 Path
    canvas.drawBitmap(mBitmapHand, mMatrix, mPaint);// 绘制手势

    invalidate(); // 重绘页面
}

}

代码分析

路径动画中主要涉及到的新的API有PathMeasureValueAnimation
下面看下代码中各个方法的作用:

init()

主要进行一些基本的初始化操作,例如Paint、Matrix、Path等的初始化。其中比较重要的有:

mPathMeasure.setPath(mPath, true);//设置为true自动闭合形成一个矩形
mLength = mPathMeasure.getLength();

后面一句代码的意思是获取到mPath的总长度,因为在后面需要使用到当前长度与总长度的比例进行绘制。

ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,1);//从0到1
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mAnimatorValue=animation.getAnimatedFraction();
            invalidate();
        }
    });
    valueAnimator.setDuration(2000L);
    valueAnimator.setRepeatCount(3);
    valueAnimator.start();

而这段代码则通过ValueAnimation来实现了动画时间、动画循环次数以及动画的启动。mAnimatorValue代表的是当前动画进行的比例(比如说现在动画进行到刚好一半,则其值就为0.5)。
当然动画也可以通过代码中注释的部分实现,但那样并不能优雅的设置其动画的时间及循环次数。

onMeasure

该方法并没进行什么操作,仅仅是获取了View宽度和高度。这里可能会涉及到getWidth()和getMeasureWidth()的区别,可以参考下:
http://blog.csdn.net/wangbofei/article/details/7795430
http://www.myexception.cn/android/2038000.html

onDraw

核心方法,这里面主要通过PathMeasure类获取当前点的坐标以及Tan值,而后修改Matrix,最终在绘制的时候传入最新的Matrix即可。
关于invalidate()和postInvalidate()的区别在前面的http://blog.csdn.net/cherish20151011/article/details/52759768已经提及到了。

使用

直接在XMl文件中使用即可

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.meitu.pathanimation.MainActivity">

<com.meitu.pathanimation.view.PathView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

相关扩展

郭神的:自定义刮刮卡效果http://blog.csdn.net/lmj623565791/article/details/40162163

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值