It’s not about how badly you want something. It’s about what you are capable of!
光有志向是不够的,重要的是你的能力。 —《疯狂动物城》
1. 概述
前述的所有动画效果叫做Tween Animation(补间动画)。而在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animation(属性动画)
- View Animation包括Tween Animation(补间动画) 和 Frame Animation(逐帧动画)
- Property Animation包括ValueAnimator 和 ObjectAnimator
直观上有如下三点不同:
- **引入时间不同:**View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0才开始有Property Animation相关的API
- **所在包名不同:**View Animation在包android.view.animation中。而Property Animation API在包 android.animation中
- 动画类的命名不同:View Animation中动画类取名都叫XXXXAnimation,而在Property Animator中动画类的取名则叫XXXXAnimator
1.1 引入Property Animator原因
- Property Animator 能实现补间动画无法实现的功能
- View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性来做动画
- 补间动画虽能对控件做动画,但并没有改变控件的内部属性值,而Property Animator则恰恰相反,通过改变控件内部的属性值来达到动画效果。
1.2 实例说明
-
布局(main.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="start anim" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:background="#ffff00" android:text="Hello qijian"/> </LinearLayout>
-
Java代码操作
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final TextView tv = (TextView) findViewById(R.id.tv); Button btn = (Button)findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final TranslateAnimation animation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 400, Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 400); animation.setFillAfter(true); animation.setDuration(1000); tv.startAnimation(animation); } }); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MyActivity.this,"clicked me",Toast.LENGTH_SHORT).show(); } }); } }
2. ValueAnimation
2.1 ValueAnimation 简单使用
关于ValueAnimation的使用主要分两步走:
-
创建ValueAnimator实例:
ValueAnimator animator = ValueAnimator.ofInt(0,400); animator.setDuration(1000); animator.start();
-
添加监听
ValueAnimator animator = ValueAnimator.ofInt(0,400); animator.setDuration(1000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int curValue = (int)animation.getAnimatedValue(); Log.d("hello","curValue:"+curValue); } }); animator.start();
从上述两步可以看出:ValueAnimator负责对数字区间做动画运算,然后对运算过程做监听,最后自己对控件做动画操作。
这里用ValueAnimator来完成前述的实例:
详细代码参见Github
2.2 ofInt与ofFloat
二者函数声明如下:
public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofFloat(float... values)
参数类型都是可变参数长参数,可以传入任何数量的值。传进去的值列表,表示动画的变化范围:比如ofInt(2,90,45)就表示从数值2变化到数字45;数字越多,变化越复杂。二者的区别是传入的数字类型不一样。
示例:
ValueAnimator animator = ValueAnimator.ofFloat(0f,400f,50f,300f);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float curValueFloat = (Float)animation.getAnimatedValue();
int curValue = curValueFloat.intValue();
tv.layout(curValue,curValue,curValue+tv.getWidth(),curValue+tv.getHeight());
}
});
animator.start();
我们在监听时,首先得到当前动画的值
Float curValueFloat = (Float)animation.getAnimatedValue();
通过getAnimatedValue()来获取当前运动点的值,大家可能会疑问为什么要转成Float类型,可以查看一下getAnimatedValue()声明:
Object getAnimatedValue();
它返回的类型是一个Object原始类型,那我们怎么知道我们要将它强转成什么类型呢。注意,我们在设定动画初始值时用的是ofFloat()函数,所以每个值的类型必定是Float类型,所以我们获取出来的类型也必然是Float类型的。同样,如果我们使用ofInt设定的初始值,那么通过getAnimatedValue()获取到的值就应该强转为Int类型。
2.3 监听器
在ValueAnimator中共有两个监听器:
/**
* 监听器一:监听动画变化时的实时值
*/
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
//添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)
/**
* 监听器二:监听动画变化时四个状态
*/
public static interface AnimatorListener {
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
//添加方法为:public void addListener(AnimatorListener listener)
AnimatorUpdateListener就是监听动画的实时变化状态。
在AnimatorListener中,主要是监听Animation的四个状态,start、end、cancel、repeat;当动画开始时,会调用onAnimationStart(Animator animation)
方法,当动画结束时调用onAnimationEnd(Animator animation)
,当动画取消时,调用onAnimationCancel(Animator animation)
函数,当动画重复时,会调用onAnimationRepeat(Animator animation)
函数。
添加AnimatorListener的方法是addListener(Animator listener);
private ValueAnimator doAnimatorListener(){
ValueAnimator animator = ValueAnimator.ofInt(0,400);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.d("TAG","animation start");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.d("TAG","animation end");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.d("TAG","animation cancel");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.d("TAG","animation repeat");
}
});
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(1000);
animator.start();
return animator;
}
取消监听
/**
* 移除AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener); //移除指定的监听器
void removeAllListeners(); // 移除所有的监听器
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
…………
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
repeatAnimator = doAnimatorListener();
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
repeatAnimator.removeAllListeners();
}
});
}
2.4 相关函数
/**
* 设置动画时长,单位是毫秒
*/
ValueAnimator setDuration(long duration)
/**
* 获取ValueAnimator在运动时,当前运动点的值
*/
Object getAnimatedValue();
/**
* 开始动画
*/
void start()
/**
* 设置循环次数,设置为INFINITE表示无限循环
*/
void setRepeatCount(int value)
/**
* 设置循环模式
* value取值有RESTART,REVERSE,
*/
void setRepeatMode(int value)
/**
* 取消动画
*/
void cancel()
/**
* 延时多久时间开始,单位是毫秒
*/
public void setStartDelay(long startDelay)
/**
* 完全克隆一个ValueAnimator实例,包括它所有的设置以及所有对监听器代码的处理
*/
public ValueAnimator clone()
示例:
private ValueAnimator doRepeatAnim(){
ValueAnimator animator = ValueAnimator.ofInt(0,400);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
}
});
animator.setDuration(1000);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(ValueAnimator.INFINITE);
return animator;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
…………
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
repeatAnimator = doRepeatAnim();
//克隆一个新的ValueAnimator,然后开始动画
ValueAnimator newAnimator = repeatAnimator.clone();
newAnimator.setStartDelay(1000);
newAnimator.start();
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
repeatAnimator.removeAllUpdateListeners();
repeatAnimator.cancel();
}
});
}
2.5 插值器
插值器也叫加速器,前面的很多例子都可以看到ValueAnimator animator = ValueAnimator.ofInt(0, 400);
,那么0~400时怎么算出来?
插值器作用,即用来控制动画区间的值是如何计算出来的。
简单使用:
ValueAnimator animator = ValueAnimator.ofInt(0,600);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
}
});
animator.setDuration(1000);
animator.setInterpolator(new BounceInterpolator());
animator.start();
如果想要自定义加速器,这里以LinearInterpolator为例,查看其源码:
/**
* An interpolator where the rate of change is constant
*/
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
LinearInterpolator继承了BaseInterpolator,而BaseInterpolator继承了Interpolator接口,Interpolator接口继承了TimeInterpolator,查看其接口:
/**
* A time interpolator defines the rate of change of an animation. This allows animations
* to have non-linear motion, such as acceleration and deceleration.
*/
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
这里是TimeInterpolator的代码,它里面只有一个函数float getInterpolation(float input)。
参数input:input参数是一个float类型,它取值范围是0到1,表示当前动画的进度,取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推
返回值:表示当前实际想要显示的进度。取值可以超过1也可以小于0,超过1表示已经超过目标值,小于0表示小于开始位置
input表示当前动画进度,返回值表示动画的数值进度,对应的数值范围由我们通过ofInt()、ofFloat()来指定,这个返回值表示当前时间所对应的数值的进度。
input参数与任何我们设定的值没关系,只与时间有关,随着时间的增长,动画的进度也自然的增加
如果需要自定义插值器,只需要实现TimeInterpolator接口即可:
public class MyInterploator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
return 1-input;
}
}
(如果要继承BaseInterpolator接口来自定义插值器,要求API最小为 22);
这里自定义的插值器将进度反转。
ValueAnimator animator = ValueAnimator.ofInt(0,600);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
}
});
animator.setDuration(1000);
animator.setInterpolator(new MyInterploator());
animator.start();
从图中可见,动画的数值进度从结束位置进行到起始位置。