Android动画类型分类
逐帧动画【Frame Animation】,即顺序播放事先做好的图像,跟电影类似
补间动画【Tween Animation】,即通过对场景里的对象不断做图像变换 ( 平移、缩放、旋转 ) 产生动画效果
属性动画【Property Animation】,补间动画增强版,支持对对象执行动画
过渡动画【Transition Animation】,实现Activity或View过渡动画效果
Android动画实现方式分类
XML资源文件
代码方式
按照时间分类
Android 3.0之前版本,逐帧动画,补间动画
Android 3.0之后版本,属性动画
Android 4.4中,过渡动画
Android逐帧动画
逐帧动画简单介绍
也叫Drawable Animation动画,是最简单最直观动画类型
逐帧动画XML资源文件方式
这个是最常用的方式,在res/drawable目录下新建动画XML文件,如下所示
android:oneshot用来控制动画是否循环播放,true表示不会循环播放,false表示会循环播放
android:duration=”200”表示每一帧持续播放的时间
逐帧动画代码方式
代码方式用的少,如下所示
AnimationDrawable drawable = new AnimationDrawable();
for(int a=0 ; a<9 ; a++){
int id = getResources().getIdentifier("audio_anim_0" + a, "mipmap", getPackageName());
Drawable da = getResources().getDrawable(id);
drawable.addFrame(da,200);
}
ivVisualEffect.setBackground(drawable);
drawable.setOneShot(false);
//获取对象实例,用来控制播放与停止 AnimationDrawable rocketAnimation = (AnimationDrawable) ivVisualEffect.getBackground();
rocketAnimation.start(); // 开启帧动画 rocketAnimation.stop(); // 停止动画
Android补间动画
补间动画简单介绍
无需关注每一帧,只需要定义动画开始与结束两个关键帧,并指定动画变化的时间与方式等 。主要有四种基本的效果
透明度变化
大小缩放变化
位移变化
旋转变化
表现形式
XML中
alph 渐变透明度动画效果
scale 渐变尺寸伸缩动画效果
translate 画面转换位置移动动画效果
rotate 画面转移旋转动画效果
JavaCode中
AlphaAnimation 渐变透明度动画效果
ScaleAnimation 渐变尺寸伸缩动画效果
TranslateAnimation 画面转换位置移动动画效果
RotateAnimation 画面转移旋转动画效果
差值器
Android系统会在补间动画开始和结束关键帧之间插入渐变值,它依据差值器。
Interpolator 时间插值类,定义动画变换的速度。能够实现alpha/scale/translate/rotate动画的加速、减速和重复等。Interpolator类其实是一个空接口,继承自TimeInterpolator,TimeInterpolator时间插值器允许动画进行非线性运动变换,如加速和限速等,该接口中只有接口中有一个方法 float getInterpolation(float input)这个方法。传入的值是一个0.0~1.0的值,返回值可以小于0.0也可以大于1.0。
提供几个Interpolator的实现类
AccelerateInterpolator 加速,开始时慢中间加速
DecelerateInterpolator 减速,开始时快然后减速
AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速
AnticipateInterpolator 反向,先向相反方向改变一段再加速播放
AnticipateOvershootInterpolator 反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2* mCycles* Math.PI* input)
LinearInterpolator 线性,线性均匀改变
OvershootInterpolator超越,最后超出目的值然后缓慢改变到目的值
PathInterpolator新增的,就是可以定义路径坐标,然后可以按照路径坐标来跑动;注意其坐标并不是 XY,而是单方向,也就是我可以从0~1,然后弹回0.5 然后又弹到0.7 有到0.3,直到最后时间结束。
AplhaAnimation
第一种方式:XML方式,如下所示
第二种方式:代码方式
AlphaAnimation alpha = new AlphaAnimation(0, 1);
alpha.setDuration(500); //设置持续时间 alpha.setFillAfter(true); //动画结束后保留结束状态 alpha.setInterpolator(new AccelerateInterpolator()); //添加差值器 ivImage.setAnimation(alpha);
ScaleAnimation
第一种方式:XML资源文件方式
第二种方式:代码方式
ScaleAnimation scale = new ScaleAnimation(1.0f, scaleXY, 1.0f, scaleXY, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scale.setDuration(durationMillis);
scale.setFillAfter(true);
ivImage.setAnimation(scale);
TranslateAnimation
第一种方式:XML资源文件方式
第二种方式:代码方式
TranslateAnimation translate = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
translate.setDuration(durationMillis);
translate.setFillAfter(true);
ivImage.setAnimation(translate);
RotateAnimation
第一种方式:XML方式
第二种方式:代码方式
RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(durationMillis);
rotate.setFillAfter(true);
ivImage.setAnimation(rotate);
Android属性动画
属性动画基本介绍
补间动画增强版本,补间动画存在一些缺点
作用对象局限:View 。即补间动画 只能够作用在视图View上,即只可以对一个Button、TextView、甚至是LinearLayout、或者其它继承自View的组件进行动画操作,但无法对非View的对象进行动画操作
没有改变View的属性,只是改变视觉效果
动画效果单一
属性动画特点
作用对象:任意 Java 对象,不再局限于 视图View对象
实现的动画效果:可自定义各种动画效果,不再局限于4种基本变换:平移、旋转、缩放 & 透明度
**基本工作原理 **
在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果
属性动画基类:Animator,抽象类。子类有两个重要的类:ValueAnimator 类 & ObjectAnimator 类,其他类:Evaluator类,AnimatorSet类
关于常用属性动画类总结如下图所示Evaluator
**估值器(TypeEvaluator)作用 **
设置动画 如何从初始值过渡到结束值的逻辑
插值器(Interpolator)决定值的变化模式(匀速、加速blabla)
估值器(TypeEvaluator)决定值的具体变化数值
看看接口TypeEvaluator 源代码
public interface TypeEvaluator {
public T evaluate(float fraction, T startValue, T endValue);
}
看看如何实现估值器
public static ValueAnimator ofArgb(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
anim.setEvaluator(ArgbEvaluator.getInstance());
return anim;
}
//-------------------- public class ArgbEvaluator implements TypeEvaluator {
private static final ArgbEvaluator sInstance = new ArgbEvaluator();
public static ArgbEvaluator getInstance() {
return sInstance;
}
// FloatEvaluator实现了TypeEvaluator接口
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
// 初始值 过渡 到结束值 的算法是:
// 1\. 用结束值减去初始值,算出它们之间的差值
// 2\. 用上述差值乘以fraction系数
// 3\. 再加上初始值,就得到当前动画的值
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}
AnimatorSet
**特点 **
单一动画实现的效果相当有限,更多的使用场景是同时使用多种动画效果,即组合动画
使用方法
第一种方式:xml方式
第二种方式:Java方式
// 步骤1:设置需要组合的动画效果 ObjectAnimator translation = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX); // 平移动画 ObjectAnimator rotate = ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f); // 旋转动画 ObjectAnimator alpha = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f); // 透明度动画 // 步骤2:创建组合动画的对象 AnimatorSet animSet = new AnimatorSet(); // 步骤3:根据需求组合动画 animSet.play(translation).with(rotate).before(alpha);
animSet.setDuration(5000); // 步骤4:启动动画 animSet.start();
常用方法
AnimatorSet.play(Animator anim) :播放当前动画
AnimatorSet.after(long delay) :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim) :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim) :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) : 将现有动画插入到传入的动画之前执行
ValueAnimator
基本作用
将初始值 以整型数值的形式 过渡到结束值 。即估值器是整型估值器 - IntEvaluator
ValueAnimator.oFloat()采用默认的浮点型估值器 (FloatEvaluator)
ValueAnimator.ofInt()采用默认的整型估值器(IntEvaluator)
第一种实现方式:Java设置
public static ValueAnimator setValueAnimator(View view , int start , int end , int time , int delay , int count){
// 步骤1:设置动画属性的初始值 & 结束值
ValueAnimator mAnimator = ValueAnimator.ofInt(start, end);
// ofInt()作用有两个
// 1\. 创建动画实例
// 2\. 将传入的多个Int参数进行平滑过渡:此处传入0和1,表示将值从0平滑过渡到1
// 如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推
// ValueAnimator.ofInt()内置了整型估值器,直接采用默认的.不需要设置,即默认设置了如何从初始值 过渡到 结束值
// 关于自定义插值器我将在下节进行讲解
// 下面看看ofInt()的源码分析 ->>关注1
mAnimator.setTarget(view);
// 步骤2:设置动画的播放各种属性
mAnimator.setDuration(time);
// 设置动画运行的时长
mAnimator.setStartDelay(delay);
// 设置动画延迟播放时间
mAnimator.setRepeatCount(count);
// 设置动画重复播放次数 = 重放次数+1
// 动画播放次数 = infinite时,动画无限重复
mAnimator.setRepeatMode(ValueAnimator.RESTART);
// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
// 步骤3:将改变的值手动赋值给对象的属性值:通过动画的更新监听器
// 设置 值的更新监听器
// 即:值每次改变、变化一次,该方法就会被调用一次
return mAnimator;
}
//------- Button b1 = (Button) findViewById(R.id.b1);
ValueAnimator valueAnimator = AnimatorUtils.setValueAnimator(b1,0, 2, 2000, 500, 2);
valueAnimator.start();
第二种实现方式:XML设置
//代码引用
Button b3 = (Button) findViewById(R.id.b3);
Animator mAnim = AnimatorInflater.loadAnimator(this, R.animator.animator_1_0);
mAnim.setTarget(b3);
mAnim.start();
ObjectAnimator
基本的原理
直接对对象的属性值进行改变操作,从而实现动画效果
继承自ValueAnimator类,即底层的动画实现机制是基于ValueAnimator类
第一种实现方式:Java设置
public static ObjectAnimator setObjectAnimator(View view , String type , int start , int end , long time){
ObjectAnimator mAnimator = ObjectAnimator.ofFloat(view, type, start, end);
// ofFloat()作用有两个
// 1\. 创建动画实例
// 2\. 参数设置:参数说明如下
// Object object:需要操作的对象
// String property:需要操作的对象的属性
// float ....values:动画初始值 & 结束值(不固定长度)
// 若是两个参数a,b,则动画效果则是从属性的a值到b值
// 若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
// 以此类推
// 至于如何从初始值 过渡到 结束值,同样是由估值器决定,此处ObjectAnimator.ofFloat()是有系统内置的浮点型估值器FloatEvaluator,同ValueAnimator讲解
// 设置动画重复播放次数 = 重放次数+1
// 动画播放次数 = infinite时,动画无限重复
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
// 设置动画运行的时长
mAnimator.setDuration(time);
// 设置动画延迟播放时间
mAnimator.setStartDelay(0);
// 设置重复播放动画模式
mAnimator.setRepeatMode(ValueAnimator.RESTART);
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
//设置差值器
mAnimator.setInterpolator(new LinearInterpolator());
return mAnimator;
}
关于preperty的属性值有,如下表所示
第二种方式:XML方式
Animator mAnim = AnimatorInflater.loadAnimator(this, R.animator.animator_1_0);
mAnim.setTarget(fabHomeRandom);
mAnim.start();
注意,以XML方式,res的文件夹名称必须是animator,否则无法引用,如下所示:
ValueAnimator与ObjectAnimator区别
ValueAnimator 类是先改变值,然后手动赋值 给对象的属性从而实现动画;是间接对对象属性进行操作;
ObjectAnimator 类是先改变值,然后自动赋值 给对象的属性从而实现动画;是直接对对象属性进行操作;
监听动画器
说明
Animation类通过监听动画开始 / 结束 / 重复 / 取消时刻来进行一系列操作,如跳转页面等等。通过在Java代码里addListener()设置,因Animator类、AnimatorSet类、ValueAnimator、ObjectAnimator类存在继承关系,所以AnimatorSet类、ValueAnimator、ObjectAnimator都可以使用addListener()监听器进行动画监听。
看看第一种监听方式
mAnim.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) {
//动画重复时执行
}
});
看看第二种监听方式
mAnim2.addListener(new AnimatorListenerAdapter() {
// 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
// 由于AnimatorListenerAdapter中已经实现好每个接口
// 所以这里不实现全部方法也不会报错
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
ToastUtils.showShort("动画结束了");
}
});
Android动画框架原理解析
要了解Android动画是如何加载出来的,我们首先要了解Android View 是如何组织在一起的.每个窗口是一颗View树. RootView是DecorView,在布局文件中声明的布局都是DecorView的子View.是通过setContentView来设置进入窗口内容的. 因为View的布局就是一棵树.所以绘制的时候也是按照树形结构来遍历每个View进行绘制.ViewRoot.java中 draw函数准备好Canvas后 调用 mView.draw(canvas),这里的mView是DecorView.
下面看一下递归绘制的几个步骤:
绘制背景
如果需要,保存画布(canvas),为淡入淡出做准备
通过调用View.onDraw(canvas)绘制View本身的内容
通过 dispatchDraw(canvas)绘制自己的孩子,dispatchDraw->drawChild->child.draw(canvas) 这样的调用过程被用来保证每个子 View 的 draw 函数都被调用
如果需要,绘制淡入淡出相关的内容并恢复保存的画布所在的层(layer)
绘制修饰的内容(例如滚动条)
当一个 ChildView 要重画时,它会调用其成员函数 invalidate() 函数将通知其 ParentView 这个 ChildView 要重画,这个过程一直向上遍历到 ViewRoot,当 ViewRoot 收到这个通知后就会调用上面提到的 ViewRoot 中的 draw 函数从而完成绘制。Android 动画就是通过 ParentView 来不断调整 ChildView 的画布坐标系来实现的。