之前我们学习了矢量动画,今天就利用适量动画制作一个支付宝支付成功后打钩的动画。其实这个动画简单描述如下:首先它会画一个圈,接着在圈内打个对勾。这个效果在很多地方都可以使用,比如提交成功,压缩成功等一系列耗时操作之后显示。好了,废话不多说,还是老规矩,一步一步跟着来。
1.分析
这个动画包含了两部分,一部分是画圈动画,另一部分是打钩动画。画圈动画结束后才开始打钩动画,所以他们是有顺序的。
2.画圈动画
animated_pay_circle.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_pay_circle_white">
<target
android:name="circle"
android:animation="@animator/anim_pay" />
</animated-vector>
anim_pay.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:interpolator/linear"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" /><!--trimPathStart就是利用0到1的百分比来按照轨迹绘制SVG图像。类似的,还有trimPathEnd这个属性。-->
vector_pay_circle_white.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="100dp"
android:viewportHeight="100"
android:viewportWidth="100"
android:width="100dp">
<path
android:name="circle"
android:pathData="
M 10,50
A 40 40 0 1 0 10 49"
android:strokeAlpha="1"
android:strokeColor="@android:color/holo_blue_dark"
android:strokeLineCap="round"
android:strokeWidth="5" />
</vector>
布局文件中activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/iv"
android:layout_centerInParent="true"/>
</RelativeLayout>
Activity中MainActivity.java
public class MainActivity extends AppCompatActivity {
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.iv);
startVectorAnim(R.drawable.animated_pay_circle);
//准备后续动画的开始
}
// 开始播放矢量动画
private void startVectorAnim(int drawableId) {
// 从指定资源编号的矢量文件中获取图形对象
Drawable mDrawable = getResources().getDrawable(drawableId);
int dip_50 = dip2px(this, 50);
iv.setImageDrawable(mDrawable);
// 将该图形强制转换为动画图形,并开始播放
((Animatable) mDrawable).start();
}
private int dip2px(Context context, float dpValue) {
// 获取当前手机的像素密度
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f); // 四舍五入取整
}
}
到这里我们就可以先运行一下了,可以看到有一个画圈的动画已经完成。
2.判断画圈结束
接着我们就要判断画圈动画结束,为打钩动画做准备。细心的同学已经看到Activity中我已经留了注释。所以我们修改Activity如下:
public class MainActivity extends AppCompatActivity {
private ImageView iv;
private Drawable mDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.iv);
startVectorAnim(R.drawable.animated_pay_circle);
//准备后续动画的开始
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 为画圈动画注册一个矢量动画图形的监听器
((AnimatedVectorDrawable) mDrawable)
.registerAnimationCallback(new VectorAnimListener());
} else {
// 延迟1秒后启动打勾动画的播放任务
new Handler().postDelayed(mHookRunnable, 1000);
}
}
// 开始播放矢量动画
private void startVectorAnim(int drawableId) {
// 从指定资源编号的矢量文件中获取图形对象
mDrawable = getResources().getDrawable(drawableId);
int dip_50 = dip2px(this, 50);
iv.setImageDrawable(mDrawable);
// 将该图形强制转换为动画图形,并开始播放
((Animatable) mDrawable).start();
}
private int dip2px(Context context, float dpValue) {
// 获取当前手机的像素密度
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f); // 四舍五入取整
}
// 定义一个动画图形的监听器
@TargetApi(Build.VERSION_CODES.M)
private class VectorAnimListener extends Animatable2.AnimationCallback {
// 在动画图形开始播放时触发
public void onAnimationStart(Drawable drawable) {}
// 在动画图形结束播放时触发
public void onAnimationEnd(Drawable drawable) {
// 开始播放打勾的矢量动画
// startVectorAnim(R.drawable.animated_pay_success);
}
}
// 定义一个打勾动画的播放任务
private Runnable mHookRunnable = new Runnable() {
@Override
public void run() {
// 开始播放打勾的矢量动画
// startVectorAnim(R.drawable.animated_pay_success);
}
};
}
3.完成打钩动画
我们既然确定了画圈动画结束的时刻,就可以开始打钩了。
animated_pay_success.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_pay_success_white">
<target
android:name="hook"
android:animation="@animator/anim_pay" />
</animated-vector>
vector_pay_success_white.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="100dp"
android:viewportHeight="100"
android:viewportWidth="100"
android:width="100dp">
<path
android:name="circle"
android:pathData="
M 10,50
A 40 40 0 1 0 10 49"
android:strokeAlpha="1"
android:strokeColor="@android:color/holo_blue_dark"
android:strokeLineCap="round"
android:strokeWidth="5" />
<path
android:name="hook"
android:pathData="
M 30,50
L 45 65
L 75 35"
android:strokeAlpha="1"
android:strokeColor="@android:color/holo_blue_dark"
android:strokeLineCap="butt"
android:strokeWidth="5" />
</vector>
修改我们的Activity代码如下
public class MainActivity extends AppCompatActivity {
private ImageView iv;
private Drawable mDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.iv);
startVectorAnim(R.drawable.animated_pay_circle);
//准备后续动画的开始
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 为画圈动画注册一个矢量动画图形的监听器
((AnimatedVectorDrawable) mDrawable)
.registerAnimationCallback(new VectorAnimListener());
} else {
// 延迟1秒后启动打勾动画的播放任务
new Handler().postDelayed(mHookRunnable, 1000);
}
}
// 开始播放矢量动画
private void startVectorAnim(int drawableId) {
// 从指定资源编号的矢量文件中获取图形对象
mDrawable = getResources().getDrawable(drawableId);
int dip_50 = dip2px(this, 50);
iv.setImageDrawable(mDrawable);
// 将该图形强制转换为动画图形,并开始播放
((Animatable) mDrawable).start();
}
private int dip2px(Context context, float dpValue) {
// 获取当前手机的像素密度
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f); // 四舍五入取整
}
// 定义一个动画图形的监听器
@TargetApi(Build.VERSION_CODES.M)
private class VectorAnimListener extends Animatable2.AnimationCallback {
// 在动画图形开始播放时触发
public void onAnimationStart(Drawable drawable) {}
// 在动画图形结束播放时触发
public void onAnimationEnd(Drawable drawable) {
// 开始播放打勾的矢量动画
startVectorAnim(R.drawable.animated_pay_success);
}
}
// 定义一个打勾动画的播放任务
private Runnable mHookRunnable = new Runnable() {
@Override
public void run() {
// 开始播放打勾的矢量动画
startVectorAnim(R.drawable.animated_pay_success);
}
};
}
这样我们就完成了一个打钩的适量动画。