安卓中动画分成两类
一种是传统动画,如:补间动画,帧动画,其本质是canvas的矩阵变换
另一种是属性动画,由谷歌从Android3.0以后推出
传统动画仅仅是视觉效果,并不会实际改变view的属性,比如:平移动画不会改变view的原来坐标,如果需要点击view还是要点击原来的位置。而属性动画不同,它是真正的改变view的属性(成员变量)。
我们使用属性动画,需要掌握5个类
- ObjectAnimator
- ValueAnimator
- PropertyValueHolder
- TypeEvaluator
- Interpolator
首先,我们创建一个ImageView,使用默认的安卓启动图标
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:onClick="startAnimation"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
下面是属性动画ObjectAnimator的基础用法
public void startAnimation(View view) {
ImageView iv = (ImageView) view;
//注意第二个参数,只要view里面有setXXX()方法就可以通过反射达到变化的目的
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
objectAnimator.setDuration(500);
objectAnimator.start();
}
ObjectAnimator.gif
如果想要多个动画同时执行
方法1.设置动画监听,同步操作其他的属性
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
//iv显然没有setXiaoming的方法,内部做了异常处理
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv, "xiaoming", 0f, 100f);
objectAnimator.setDuration(500);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 监听动画回调
//animation.getAnimatedFraction();//动画执行的百分比 0~1 //API 12+
float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
iv.setScaleX(0.5f+value/200);
iv.setScaleY(0.5f+value/200);
//iv.setTranslationX(value);
}
});
objectAnimator.start();
}
设置动画监听,同步操作其他的属性.gif
方法2.使用ValueAnimator,如果只需要监听值变化就用ValueAnimator
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
ValueAnimator animator = ValueAnimator.ofFloat(0f, 200f);
animator.setDuration(200);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
iv.setScaleX(0.5f + value / 200);
iv.setScaleY(0.5f + value / 200);
}
});
animator.start();
}
ValueAnimator.gif
方法3.使用PropertyValuesHolder
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.5f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, holder1, holder2, holder3);
animator.setDuration(200);
animator.start();
}
PropertyValuesHolder.gif
方法4.动画集合AnimatorSet
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv, "alpha", 0f, 1f);
// animator2.setStartDelay(startDelay)//设置延迟执行
ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv, "scaleX", 0f, 2f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
// animatorSet.play(animator3).with(animator2).after(animator1);//animator1在前面
// animatorSet.play(animator3).with(animator2).before(animator1);//animator1在后面
// animatorSet.playTogether(animator1,animator2,animator3);//同时执行
animatorSet.playSequentially(animator1, animator2, animator3);//按顺序执行
animatorSet.start();
}
AnimatorSet.gif
如果我们要实现一个自由落体抛物线动画,可以使用估值器TypeEvaluator
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
ObjectAnimator objectAnimator = new ObjectAnimator();
objectAnimator.setDuration(2000);
objectAnimator.setObjectValues(new PointF(0, 0));
final PointF pointF = new PointF();
objectAnimator.setEvaluator(new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//估值计算方法---可以在执行的过程当中干预改变属性的值---做效果:用自己的算法来控制
//不断地去计算修改坐标
//x匀速运动 x=v*t
pointF.x = 400f * (fraction);
//加速度 y=vt=1/2*g*t*t
pointF.y = (float) (10f * 0.5f * 9.8f * Math.pow(fraction * 5, 2));
return pointF;
}
});
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF1 = (PointF) animation.getAnimatedValue();
iv.setX(pointF1.x);
iv.setY(pointF1.y);
}
});
objectAnimator.start();
}
自由落体抛物线.gif
动画执行过程,我们想要控制它的执行速度,可以使用插值器(加速器)Interpolater,下面介绍了几种常用的插值器
public void startAnimation(View view) {
final ImageView iv = (ImageView) view;
ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationY", 0f,1000f);
oa.setDuration(800);
oa.setInterpolator(new AccelerateDecelerateInterpolator());
oa.start();
}
AccelerateDecelerateInterpolator 加速减速插值器 .png
AccelerateDecelerateInterpolator .gif
AccelerateInterpolator 加速插值器.png
AccelerateInterpolator .gif
AnticipateInterpolator 回荡秋千插值器 .png
AnticipateInterpolator.gif
AnticipateOvershootInterpolator.png
AnticipateOvershootInterpolator.gif
BounceInterpolator 弹跳插值器.png
BounceInterpolator .gif
CycleInterpolator 正弦周期变化插值器 .png
CycleInterpolator .gif
DecelerateInterpolator 减速插值器.png
DecelerateInterpolator .gif
OvershootInterpolator.png
OvershootInterpolator.gif