`# 前言
- Android群英传读书笔记
// SVG部分待补充
目录
Android View动画框架
- Animation框架定义了几种常见动画
- 透明度 AlphaAnimation
- 旋转 RotateAnimation
- 缩放 ScaleAnimation
- 位移 TranslateAnimation
- 动画合集 AnimatorSet
- 实现原理
- 每次绘制视图View所在ViewGroup中drawChild函数获取该View的Animation的Transformation值
- 调用canvas.concat(transformToApply.getMatrix())
- 通过矩阵运算完成动画帧
- 如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画
- 从而完成整个动画的绘制
- 缺点:不具备交互性,视图动画结束,但响应事件位置不变
- 优点:效率高,使用方便
Android属性动画
- 可以响应事件
- 通常是AnimatorSet和ObjectAnimator配合
- ObjectAnimator能够自动驱动
ObjectAnimator
- 创建一个ObjectAnimator只需要通过它的静态工厂类直接返回一个ObjectAnimator对象
- 参数包括一个对象和对戏那个的属性名,但这个属性必须有Set和Get方法,内部会通过反射机制调用Set方法修改对象属性值
// 简单的位移动画
ObjectAnimator animator = ObjectAnimator.ofFloat(
view,
"translationX",
300
);
animator.setDuration(300);
animator.start();
属性 |
作用 |
translationX、translationY |
作为增量控制View对象从它布局容器的左上角坐标偏移的位置 |
rotation、rotationX、rotationY |
控制View对象围绕支点进行2D和3D旋转 |
scaleX、scaleY |
控制View对象围绕支点进行2D缩放 |
pivotX、pivotY |
控制View对象的支点位置,围绕这个支点进行旋转和缩放变换处理,默认情况下,该支点的位置就是View对象的中心点 |
x、y |
描述View对象在他容器的最终位置,是最初左上角坐标和translationX、translationY值得累计和 |
alpha |
View对象的透明度,默认为1,0为完全透明 |
- 属性动画的机制是通过反射调用Set和Get方法,如果一个属性没有Get和Set方法应该怎么办?google在应用层提供了两种解决方法
- 通过自定义一个属性类或者包装类来间接的给这个属性增加get、set方法
- 通过ValueAnimator来实现
private static class WrapperView {
private View mTraget;
public WrapperView(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
- 通过上面的方法给属性动画包装一层,并提供了Get、Set方法
ViewWrapper wrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();
PropertyValuesHolder
- 针对同一个对象的多个属性,可以使用PropertyValuesHolder
PropertyValuesHolder pv1 = PropertyValuesHolder.ofFloat("translationX", 300);
PropertyValuesHolder pv2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pv3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pv1,pv2,pv3).setDuration(2000).start();
ValueAnimator
- ObjectAnimator继承自ValueAnimator
- 可以看作一个数值发生器,用来产生有规律的数字
- AnimatorUpdateListener监听数值变换
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
//do the animation!
}
});
动画事件监听
- 一个完整的动画具有Start、Repeat、End、Cancel四个过程
- 当然一般用到最多的是End监听
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
});
AnimatorSet
- 同样是对一个控件添加多个动画,AnimatorSet比PropertyValuesHolder多了精确控制动画顺序的功能
- 还是上面的例子
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 300f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(2000);
set.playTogether(animator1,animator2,animator3);
set.start();
API |
作用 |
playTogether() |
一起播放 |
playSequentially() |
顺序播放 |
animSet.play(anim1).with(anim2) |
anim1和anim2一起播放 |
animSet.play(anim1).before(anim2) |
anim1在anim2之前播放 |
animSet.play(anim1).after(anim2) |
anim1在anim2之后播放 |
XML中使用属性动画
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);
anim.setTarget(view);
anim.start();
View的animate方法
- Android3.0之后,View自带animate方法直接驱动属性动画(相当于简写方法)
view.animate()
.alpha(0)
.y(300)
.setDuration(3000)
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
}
}).start();
Android布局动画
- 作用在ViewGroup上,给ViewGroup增加View时添加一个动画过渡效果
- 最简单的例子
android:animateLayoutChanges="true"
- 或者使用LayoutAnimationController类自定义一个View过渡效果
- LayoutAnimationController.ORDER_NORMAL-- 顺序
- LayoutAnimationController.ORDER_RANDOM-- 随机
- LayoutAnimationController.ORDER_REVERSE-- 逆序
LinearLayout ll = (LinearLayout)findViewById(R.id.ll);
// 设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0,1,0,1);
sa.setDuration(2000);
// 设置布局动画的显示属性
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5F);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
// 为ViewGroup设置布局动画
ll.setLayoutAnimation(lac);
自定义动画
- 实现applyTransformation即可
- 根据情况覆盖父类initialize方法实现一些初始化工作
/**
* 电视机关闭效果
*/
public class CustomTV extends Animation {
// 中心点坐标
private int mCenterWidth;
private int mCenterHeight;
/**
* 实现初始化操作
*/
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(1000);
// 动画结束后保留状态
setFillAfter(true);
// 设置默认插值器
setInterpolator(new AccelerateInterpolator());
mCenterWidth = width / 2;
mCenterHeight = height / 2;
}
/**
* 参数1:interpolatedTime:插值器的时间因子,由动画当前完成的百分比和当前时间所对应的插值计算得来,取值范围0到1.0
* 参数2:Transformation:矩阵的封装类,一般使用这个类获得当前的矩阵对象
*/
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// 获得当前矩阵对象
final Matrix matrix = t.getMatrix();
// 通过改变matrix对象,实现动画效果
matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight);
}
}