视图动画定义了透明度AlphaAnimation、旋转RotateAnimation、缩放ScaleAnimation、位移TranslateAnimation四种基本动画,还提供AnimationSet动画集合,混合使用多种动画。
原理:
1. 每次绘制时,View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值
2. 调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧
3. 如果一次绘制结束,动画没有完成,就继续调用invalidate,启动下次绘制,知道动画绘制完成
另外
Animation也提供了对应得监听回调,监听动画开始、结束、重复事件
视图动画改变的只是显示,并不能响应事件。而属性动画也可以让控件的对事件的监听转移位置。最常使用的就是AnimatorSet和ObjectAnimator。
一般形式:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 300);
animator.setDuration(1000);
animator.start();
ObjectAnimator使用静态工厂方法生成动画对象,第一个参数为要控制的对象,第二个参数为要控制的属性值(该属性必须有get和set方法,因为实现原理就是通过Java的反射机制调用set函数修改对象属性值),第三个参数该属性变化的取值(也可以是数组)
常用的可以直接使用属性动画的属性包括:
a)自定义属性类或包装类,添加get、set方法
public class WrapperView {
private View mView;
public WrapperView(View mView){
this.mView = mView;
}
public int getWidth(){
return mView.getLayoutParams().width;
}
public void setWidth(int width){
mView.getLayoutParams().width = width;
mView.requestLayout();
}
}
b)通过ValueAnimator实现
本节后续会介绍
ObjectAnimator就是继承自ValueAnimator的,它是属性动画的核心,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、Cancle四个过程,Android提供接口监听这四个事件
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
大多数时候,只需要关心动画什么时候结束,就可以使用Android的简易适配器AnimatorListenerAdapter,其实它就是实现了接口AnimatorListener的抽象类,这样具体想监听那个具体事件就继承并重写那个方法即可
animator1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("rotation", 360);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(propertyBt, pvh1, pvh2, pvh3).setDuration(1000).start();
属性动画集合AnimatorSet:控制多个动画的协同工作方式,常用方法animatorSet.play().with().before().after()、playTogether、playSequentially等方法来精确控制动画播放顺序。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(animBt, "rotation", 360);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(animBt, "scaleX", 1f, 0, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(animBt, "scaleY", 1f, 0, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playSequentially(animator1, animator2, animator3);
set.start();
更推荐使用AnimatorSet,既可以与PropertyValuesHolder一样实现几个属性动画同时使用,也可以定义几个动画的先后顺序
在animator文件夹下定义属性动画
<objectAnimator xmlns:app="http://schemas.android.com/apk/res/android"
app:duration="1000"
app:propertyName="scaleX"
app:valueFrom="1.0"
app:valueTo="2.0"
app:valueType="floatType">
objectAnimator>
在代码中使用
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.anim);
anim.setTarget(xmlBt);
anim.start();
属性动画的简写方式
imageView.animate().alpha(0).y(100).setDuration(1000)
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
ViewGroup增加View时的动画,使用以下代码打开系统默认的动画
android:animateLayoutChanges="true"
自定义布局动画
LinearLayout ll = (LinearLayout) findViewById(R.id.layout_anim);
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
sa.setDuration(2000);
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
ll.setLayoutAnimation(lac);
定义动画变化速率,类似加速度。
创建自定义动画就是要实现它的applyTransformation的逻辑,不过通常还需要覆盖父类的initialize方法来实现初始化工作。
applyTransformation(float interpolatedTime, Transformation t)
第一个参数interpolatedTime差值器的时间因子
第二个参数Transformation,矩阵封装类,一般使用此类获取当前的矩阵对象:
final Matrix matrix = mTransformation.getMartix()
通过改变matrix对象,可将动画效果显示出来,matrix的变化基本可实现任何动画效果
模拟电视关闭动画
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;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final Matrix matrix = t.getMatrix();
matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight);
}
}
3D动画
使用android.graphics.Camera中的Camera类,它封装了OpenGL的3D动画。可以把Camera想象成一个真实的摄像机,当物体固定在某处时,只要移动摄像机就能拍摄到具有立体感的图像,因此通过它可以实现各种3D效果。
public class CustomAnim extends Animation {
private int mCenterWidth;
private int mCenterHeight;
private Camera mCamera = new Camera();
private float mRotateY = 0.0f;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(2000);// 设置默认时长
setFillAfter(true);// 动画结束后保留状态
setInterpolator(new BounceInterpolator());// 设置默认插值器
mCenterWidth = width / 2;
mCenterHeight = height / 2;
}
// 暴露接口-设置旋转角度
public void setRotateY(float rotateY) {
mRotateY = rotateY;
}
@Override
protected void applyTransformation( float interpolatedTime, Transformation t) {
final Matrix matrix = t.getMatrix();
mCamera.save();
mCamera.rotateY(mRotateY * interpolatedTime);// 使用Camera设置旋转的角度
mCamera.getMatrix(matrix);// 将旋转变换作用到matrix上
mCamera.restore();
// 通过pre方法设置矩阵作用前的偏移量来改变旋转中心
matrix.preTranslate(mCenterWidth, mCenterHeight);
matrix.postTranslate(-mCenterWidth, -mCenterHeight);
}
}
挖坑待填-_-