文章目录
属性动画
概述
- Android3.0之前的动画框架存在一些缺陷,动画改变的只是显示,并不能响应事件。
- 在Android3.0之后,谷歌推出全新的动画框架,实现机制是通过对目标对象进行赋值并修改其属性来实现的 。
ObjectAnimator
ObjectAnimator可以直接对任意对象的任意属性进行动画操作。
基本属性
public class Constant {
public static final String TRANSLATION_X = "translationX";
public static final String TRANSLATION_Y = "translationY";
public static final String SCALE_X = "scaleX";
public static final String SCALE_Y = "scaleY";
public static final String ROTATION = "rotation";
public static final String ALPHA = "alpha";
}
旋转动画
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, ROTATION, 0f, 360f);
animator.setDuration(2000L);
animator.setRepeatCount(3);
animator.start();
平移动画
float distance = imageView.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, TRANSLATION_X, distance, 500, distance);
animator.setDuration(2000L);
animator.setRepeatCount(3);
animator.start();
缩放动画
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, SCALE_Y, 1f, 3f, 1f);
animator.setDuration(2000L);
animator.start();
透明度动画
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, ALPHA, 1f, 0f, 1f);
animator.setDuration(2000L);
animator.start();
组合动画
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
float distance = imageView.getTranslationX();
ObjectAnimator translation = ObjectAnimator.ofFloat(imageView, TRANSLATION_X, distance, 500, distance);
ObjectAnimator scale = ObjectAnimator.ofFloat(imageView, SCALE_Y, 1f, 3f, 1f);
ObjectAnimator rotation = ObjectAnimator.ofFloat(imageView, ROTATION, 0f, 360f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, ALPHA, 1f, 0f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
//1.同时执行动画一
// animatorSet.play(translation).with(scale).with(rotation).with(alpha);
//2.同时执行动画二
// animatorSet.playTogether(translation, scale, rotation, alpha);
//3.顺序执行动画
// animatorSet.playSequentially(translation, scale, rotation, alpha);
//4.指定顺序执行动画:rotation->translation->scale
animatorSet.play(translation).before(scale).after(rotation);
animatorSet.setDuration(2000);
animatorSet.start();
ValueAnimator
- ObjectAnimator类是属性动画中最核心的类,ObjectAnimator继承于ValueAnimator
- 属性动画是通过不断修改值实现动画效果,而初始值和结束值之间的变化由该类负责计算
//向右移动500
private void startValueAnimator() {
int distance = 500;
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(2000L);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
moveView(imageView, value, distance);
}
});
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
}
private void moveView(View targetView, float value, int distance) {
int left = rawLeft + (int) (value * distance);
int top = targetView.getTop();
int right = left + targetView.getWidth();
int bottom = top + targetView.getHeight();
targetView.layout(left, top, right, bottom);
}
Interpolator 插值器
作用:设置属性值从初始值过渡到结束值的变化规律,通过操作动画之下的进度(0%-100%)计算属性值
Android系统内置9种插值器
- 匀速:资源ID
@android:anim/linear_interpolator
Java类LinearInterpolator
- 减速:资源ID
@android:anim/decelerate_interpolator
Java类DecelerateInterpolator
- 加速:资源ID
@android:anim/accelerate_interpolator
Java类AccelerateInterpolator
- 快速完成动画,超出再回到结束样式:资源ID
@android:anim/overshoot_interpolator
Java类OvershootInterpolator
- 先加速再减速:资源ID
@android:anim/accelerate_decelerate_interpolator
Java类AccelerateDecelerateInterpolator
- 先退后再加速前进:资源ID
@android:anim/anticipate_interpolator
Java类AnticipateInterpolator
- 先退后再加速前进,超出终点后再回终点:资源ID
@android:anim/anticipate_overshoot_interpolator
Java类AnticipateOvershootInterpolator
- 最后阶段弹球效果:资源ID
@android:anim/bounce_interpolator
Java类BounceInterpolator
- 周期运动:资源ID
@android:anim/cycle_interpolator
Java类CycleInterpolator
说明:在XML文件中使用资源ID,在代码中使用差值器对象
使用系统插值器
ArrayList<Interpolator> interpolators = new ArrayList<Interpolator>() {
{
add(new LinearInterpolator());//匀速
add(new DecelerateInterpolator());//减速
add(new AccelerateInterpolator());//加速
add(new OvershootInterpolator());//快速完成动画,超出再回到结束样式
add(new AccelerateDecelerateInterpolator());//先加速再减速
add(new AnticipateInterpolator());//先退后再加速前进
add(new AnticipateOvershootInterpolator());//先退后再加速前进,超出终点后再回终点
add(new BounceInterpolator());//最后阶段回弹效果
add(new CycleInterpolator(3));//周期运动
}
};
for (int i = 0; i < textViews.size(); i++) {
TextView textView = textViews.get(i);
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, Constant.TRANSLATION_X, 0, 1000F);
animator.setDuration(5000L);
animator.setInterpolator(interpolators.get(i));
animator.start();
}
自定义差值器
public class MyInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
Log.e("TAG", "input: " + input);
input = input - 0.5f;
return (float) Math.sin(60 * input) + 0.5f;
}
}
TypeEvaluator 估值器
作用:通过设置属性值从初始值过渡到结束值的变化具体数值
动画的值 = 初始值 + 完成度 * (结束值 - 初始值)
实现了TypeEvaluator
接口,然后重写了evaluate()
方法,参数有三个,依次是:
- fraction:动画的完成度,我们根据他来计算动画的值应该是多少
- startValue:动画的起始值
- endValue:动画的结束值
private void startTypeEvaluator() {
ValueAnimator valueAnimator = ValueAnimator.ofObject(new FloatEvaluator(), 0f, 1f);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
Log.e("TAG", "value:" + value);
}
});
valueAnimator.start();
}
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
打印信息
value:0.0
value:0.0
value:0.033116043
value:0.26119065
...
value:0.89794815
value:0.97329646
value:1.0
ViewPropertyAnimator
属性动画的机制已经不是再针对于View而进行设计的了,而是一种不断地对值进行操作的机制,它可以将值赋值到指定对象的指定属性上。但是,在绝大多数情况下,我相信大家主要都还是对View进行动画操作的。Android开发团队也是意识到了这一点,没有为View的动画操作提供一种更加便捷的用法确实是有点太不人性化了,于是在Android 3.1系统当中补充了ViewPropertyAnimator这个机制。
//透明度动画
imageView.animate().alpha(0.5f).setDuration(2000L);
ViewCompat.animate(imageView).alpha(0.5f);
//平移动画
imageView.animate().translationX(500f).setDuration(2000L);
//旋转动画
imageView.animate().rotation(360).setDuration(2000L);
//缩放动画
imageView.animate().scaleX(1.5F).setDuration(2000L);
ObjectAnimator 高级用法
public class MyAnimView extends View {
public static final int RADIUS = 50;
private Point currentPoint;
private Paint mPaint;
public MyAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
private void drawCircle(Canvas canvas) {
float x = currentPoint.x;
float y = currentPoint.y;
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void setColor(String color) {
mPaint.setColor(Color.parseColor(color));
}
private void startAnimation() {
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth(), getHeight());
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
ObjectAnimator anim2 = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(), "#0000FF", "#FF0000");
anim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setColor((String) animation.getAnimatedValue());
invalidate();
}
});
AnimatorSet animSet = new AnimatorSet();
animSet.play(anim).with(anim2);
animSet.setDuration(5000);
//速度加快
//animSet.setInterpolator(new AccelerateInterpolator(2f));
//弹跳效果
animSet.setInterpolator(new BounceInterpolator());
animSet.start();
}
public class PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//fraction:动画的完成度
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
int x = (int) (startPoint.x + fraction * endPoint.x - startPoint.x);
int y = (int) (startPoint.y + fraction * endPoint.y - startPoint.y);
Point point = new Point(x, y);
return point;
}
}
public class ColorEvaluator implements TypeEvaluator {
private int mRed = -1;
private int mGreen = -1;
private int mBlue = -1;
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
String startColor = (String) startValue;
String endColor = (String) endValue;
int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
// 初始化颜色的值
if (mRed == -1) {
mRed = startRed;
}
if (mGreen == -1) {
mGreen = startGreen;
}
if (mBlue == -1) {
mBlue = startBlue;
}
// 计算初始颜色和结束颜色之间的差值
int redDiff = Math.abs(startRed - endRed);
int greenDiff = Math.abs(startGreen - endGreen);
int blueDiff = Math.abs(startBlue - endBlue);
int colorDiff = redDiff + greenDiff + blueDiff;
if (mRed != endRed) {
mRed = getCurrentColor(startRed, endRed, colorDiff, 0, fraction);
} else if (mGreen != endGreen) {
mGreen = getCurrentColor(startGreen, endGreen, colorDiff, redDiff, fraction);
} else if (mBlue != endBlue) {
mBlue = getCurrentColor(startBlue, endBlue, colorDiff, redDiff + greenDiff, fraction);
}
// 将计算出的当前颜色的值组装返回
String currentColor = "#" + getHexString(mRed) + getHexString(mGreen) + getHexString(mBlue);
return currentColor;
}
/**
* 根据fraction值来计算当前的颜色。
*/
private int getCurrentColor(int startColor, int endColor, int colorDiff,
int offset, float fraction) {
int currentColor;
if (startColor > endColor) {
currentColor = (int) (startColor - (fraction * colorDiff - offset));
if (currentColor < endColor) {
currentColor = endColor;
}
} else {
currentColor = (int) (startColor + (fraction * colorDiff - offset));
if (currentColor > endColor) {
currentColor = endColor;
}
}
return currentColor;
}
/**
* 将10进制颜色值转换成16进制。
*/
private String getHexString(int value) {
String hexString = Integer.toHexString(value);
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
return hexString;
}
}
}