(一)简介
属性动画是Android 3.0中提供了新功能,便于对任意元素进行“平滑的过渡”。众所周知,Android 之前提供的补间动画如AlphaAnimation、TranslateAnimation等都只能应用在View上,并且几乎没有任何可扩展的地方。并且,使用原来的动画无法实现颜色渐变效果,算是一个遗憾。
属性动画彻底打破了这种设计方式,不再将这些动画强制的放在View上,而是仅仅产生一系列的值,由开发人员自行使用这些值。例如,属性动画可产生1~0平滑过渡的值,把这些值应用在View的alpha上就可以实现透明度渐变了。
同时,属性动画可以直接用来改变View的属性。例如,不断的setTranslationX,便可实现水平方向的平移。
(二)代码演示
1.ValueAnimator:产生某个范围内平滑过渡的值。
//属性动画,0~1渐变
public void simpleValueAnimator(View view) {
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
//动画过程的监听
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//回调方法在主线程执行
float currentValue = (float) animation.getAnimatedValue();
Log.d(TAG, "current value is " + currentValue);
}
});
anim.start();
}
(1)该方法可以通过设置多个值来实现更复杂的“平滑过渡”,例如实现0~5~3~10的过渡效果:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
(2)设置启动延时、重复次数、重复模式:
//设置启动延时
anim.setStartDelay(1000);
//设置重复次数(也可以设置成无限次数)
anim.setRepeatCount(3);
//设置重复模式:重新执行动画(也可以设置成倒序)
anim.setRepeatMode(ValueAnimator.RESTART);
(3)监听动画开始、结束、重复状态:
//监听动画的状态(开始/结束/重复/取消)
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
Log.d(TAG, "onAnimationStart");
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
Log.d(TAG, "onAnimationRepeat");
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Log.d(TAG, "onAnimationEnd");
}
});
2.ObjectAnimator:平滑的改变任意对象的属性值。
(1)平滑改变TextView的不透明度:
public void changeAlphaValue(View view) {
TextView textView = (TextView) findViewById(R.id.main_text1);
//ObjectAnimator继承自ValueAnimator
//animator会调用textView的setAlpha方法。如果该方法不存在则会出现警告异常。
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0f, 1f);
animator.setDuration(3000);
animator.start();
}
该动画并非直接改变textView的alpha属性(事实上,textView甚至它的父组件View都没有alpha属性),而是调用textView的setAlpha方法,然后传入1~0~1平滑渐变的值作为参数,从而实现了不透明度渐变效果。
类似的,可以通过传递参数rotation、translationX(translationY)等实现旋转、平移等效果。
3.使用AnimatorSet将各个动画进行组合:
public void animatorSet(View view) {
TextView textView = (TextView) findViewById(R.id.main_text1);
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textView, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textView, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0.2f, 1f);
//先平移,然后在旋转的同时进行alpha渐变
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
}
animSet.play会产生一个Animator.Builder对象,然后可以使用with,after,before等方法进行动画叠加。
4.自定义Evaluator,实现任意两个对象之间的“平滑过渡”。
ValueAnimator的ofInt,ofFloat方法很简单,无非是产生一些平滑过渡的数值。不过,ValueAnimator还有一个ofObject方法,可以实现两个Object之间的平滑过渡。显然,系统不可能知道应该怎么过渡,因此需要我们指定它。
例如定义了一个类表示点的坐标:
public class PointBean {
private float x;
private float y;
public PointBean(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
}
然后,我们希望实现两个点之间的平滑过渡(通过它就可以实现View的平移了),就需要定义两个PointBean之间是如何过渡的。当然此处的实现很简单:
public class PointEvaluator implements TypeEvaluator<PointBean> {
@Override
public PointBean evaluate(float fraction, PointBean startValue, PointBean endValue) {
float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
return new PointBean(x, y);
}
}
参数fraction表示动画完成度(0.0~1.0的一个值),startValue表示开始点,endValue表示结束点,该方法需要返回从startValue过渡到endValue、完成比例是fraction时的结果。
然后,通过两个PointBean的过渡实现平移效果(此处仅为示意,实际场景中可以直接使用ObjectAnimator):
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointBean current = (PointBean) animation.getAnimatedValue();
imageView.setTranslationX(current.getX());
imageView.setTranslationY(current.getY());
}
});
animator.start();
5.实现颜色渐变
与上述内容相似,实现红色~绿色~蓝色的渐变:
ValueAnimator animator = ValueAnimator.ofObject(new ColorEvaluator(), "#ffff0000", "#ff00ff00", "#ff0000ff");
animator.setDuration(5000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
String currentColor = (String) animation.getAnimatedValue();
textView.setBackgroundColor(Color.parseColor(currentColor));
}
});
animator.start();
显然此处的重点是ColorEvaluator,即指定颜色值是如何渐变的。例如, #ffff0000是如何过渡到#ff00ff00的。
public class ColorEvaluator implements TypeEvaluator<String> {
//仅支持AARRGGBB模式
@Override
public String evaluate(float fraction, String startValue, String endValue) {
if (!startValue.startsWith("#") || !endValue.startsWith("#")) {
throw new IllegalArgumentException("color must started with '#'.");
}
if (startValue.length() != 9 || endValue.length() != 9) {
throw new IllegalArgumentException("startValue and endValue must be '#AARRGGBB'.");
}
int start_a, start_r, start_g, start_b;
int end_a, end_r, end_g, end_b;
//start
start_a = getIntValue(startValue, 1, 3);
start_r = getIntValue(startValue, 3, 5);
start_g = getIntValue(startValue, 5, 7);
start_b = getIntValue(startValue, 7, 9);
//end
end_a = getIntValue(endValue, 1, 3);
end_r = getIntValue(endValue, 3, 5);
end_g = getIntValue(endValue, 5, 7);
end_b = getIntValue(endValue, 7, 9);
return "#" + getHexString((int) (start_a + fraction * (end_a - start_a)))
+ getHexString((int) (start_r + fraction * (end_r - start_r)))
+ getHexString((int) (start_g + fraction * (end_g - start_g)))
+ getHexString((int) (start_b + fraction * (end_b - start_b)));
}
//从原始#AARRGGBB颜色值中指定位置截取,并转为int.
private int getIntValue(String hexValue, int start, int end) {
return Integer.parseInt(hexValue.substring(start, end), 16);
}
private String getHexString(int value) {
String a = Integer.toHexString(value);
if (a.length() == 1) {
a = "0" + a;
}
return a;
}
}
6.设置Interpolator,控制动画进行的方式,如匀速、逐渐加速、逐渐减速或先加速后减速等效果。此处和传统的动画很相似。同样,可以自定义Interpolator的实现。
anim.setInterpolator(new AccelerateInterpolator()); //逐渐加速的动画
7.ViewPropertyAnimator:使用属性动画为View设置动画效果的一种简便方式。
testImageView.animate().setDuration(2000).alpha(0.3f).rotationBy(360).yBy(160);
上述代码表示将testImageView的不透明度渐变至0.3,同时旋转360度、向下移动160px。
这里的方法都有两种形式,如rotation(360)表示旋转至360度的位置(不管起始状态是多少度,都旋转至360度),而rotationBy(360)表示旋转360度(如果起始位置不是0度,则结束时依然不是0度)。