读书笔记(7) Android动画深入分析

这些读书笔记是根据《Android开发艺术探索》和《Android群英传》这两本书,然后将书上的一些知识点做一下记录。方便学习和理解,如果有存在侵犯版权的地方,还麻烦告知。个人强烈建议购买这两本书。真心不错。

本节是和《Android开发艺术探索》中的第7章 “Android动画深入分析” 有关系,建议先买书查看这一章。

[]

Android动画分为三种:View动画,帧动画,属性动画。

View动画通过对View对象不断做图像变换(平移,缩放,旋转,透明度)从而产生动画效果。

帧动画通过顺序播放一系列图像从而产生动画效果。可以简单理解为图片切换动画。

属性动画通过动态改变对象的属性从而产生动画效果。属性动画为API 11的新特性。在低于API 11无法使用属性动画,但是可以通过NineOldAndroids兼容库来使用。

View动画只对动画的起始值和结束值进行赋值,而动画中间执行过程中的属性值则是系统帮我们计算的。属性动画可以控制动画执行过程中的任意时刻的任意属性值。

[]View动画

View动画的作用对象是View,View动画支持4种动画效果:平移动画,缩放动画,旋转动画,透明度动画。View动画还支持自定义。

View动画既可以通过xml来定义,也可以通过代码来动态创建,但是对于View动画来说,建议采用xml来定义动画,因为xml格式的动画可读性更好。

如果采用xml格式来定义动画,可以将动画xml文件存放到res/anim

{}动画集合(AnimationSet < set >)

动画集合可以包括多个动画。




{}平移动画(TranslateAnimation < translate >)

可以使View在水平和竖直方向完成平移的动画效果。

< translate >标签属性:



    


{}缩放动画(ScaleAnimation < scale>)

可以使View具有放大或者缩小的动画效果。

< scale>标签属性:



    


默认情况下轴点是View的左上角,这时在水平方向缩放会导致View向左右两个方向同时进行缩放。如果轴点是View的右边界,那么View就只会向左边进行缩放。

{}旋转动画(RotateAnimation < rotate>)

可以使View具有旋转的动画效果。

< rotate>标签属性:



     


View是围绕着轴点进行旋转的。默认情况下轴点是View的左上角。

注:坐标的值可以有三种格式:以”%”后缀结束,表示相对于View本身的百分比;如果以”%p”后缀结束,表示相对于父View的百分比;如果没有任何后缀,表示相对于View本身具体值。

{}透明度动画(AlphaAnimation < alpha>)

可以改变View的透明度。

< alpha>标签属性:



    



透明度中0.0为全透明,1.0为不透明,默认为1.0。

{}加载View动画和View动画监听

//加载View动画

Animation animationText= AnimationUtils.loadAnimation(this,R.anim.anim_text);
mTextView.startAnimation(animationText);

//View动画监听

 animationText.setAnimationListener(AnimationListener listener);

AnimationListener 接口有三个方法:

void onAnimationStart(Animation animation); //动画开始
void onAnimationEnd(Animation animation); //动画结束
void onAnimationRepeat(Animation animation); //动画重复播放

{}自定义View动画

继承Animation类,重写initialize()和applyTransformation(),其中在initialize()中对一些变量进行初始化工作, 在applyTransformation()中通过矩阵修改动画数值,从而控制动画的实现过程。很多时候采用Camera来简化矩阵变换,其实自定义View动画主要是矩阵变换的过程。在实际开发过程中很少使用自定义View动画。

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {

    Matrix matrix = t.getMatrix();
    ......

    super.applyTransformation(interpolatedTime, t);
}

float interpolatedTime参数:表示当前动画进行的时间与动画总时间(一般在 setDuration() 方法中设置)的比值,从0逐渐增大到1

Transformation t参数:传递当前动画对象,一般可以通过代码 Matrix matrix = t.getMatrix() 获得 Matrix 矩阵对象,再设置 Matrix 对象,一般要用到 interpolatedTime 参数,以此达到控制动画实现的结果。

t参数: 传递当前动画对象。

applyTransformation()在动画的执行过程中会不断地调用。通过t.getMatrix() 获得 Matrix(矩阵),一般要用到 interpolatedTime 参数来设置Matrix,以此达到控制动画实现的结果。

[]帧动画(AnimationDrawable < animation-list >)

帧动画xml文件存放到res/drawable,

//定义帧动画xml文件



    
    


必须要将帧动画作为View的背景,可以通过代码也可以通过xml设置。

mButton.setBackgroundResource();

 <....View
    .... 
    android:background="@drawable/...." />

开始帧动画

AnimationDrawable animDrawable=(AnimationDrawable)mButton.getBackground()
animDrawable.start();

[]View动画的特殊使用场景

{}ViewGroup控制子元素的出场效果

LayoutAnimation作用于ViewGroup,这样它的子元素出场就会具有动画效果,这种效果主要用在ListView上,它的每个item都以一定的动画的形式出现。


android:delay属性:表示子元素开始动画的时间延迟。比如子元素的入场动画的时间周期是300ms,那么0.5表示每一个子元素都要延迟150ms才能播放入场动画。

android:animation属性:为子元素指定具体的入场动画。

android:animationOrder属性:表示子元素动画的顺序。有3个值分别是:normal,reverse,random。其中normal表示顺序显示,即排在前面的子元素先开始播放入场动画。reverse表示逆向显示,即排在后面的子元素先开始播放入场动画。random表示随机播放入场动画。

为ViewGroup指定android:layoutAnimation=”@anim/……”,对于ListView来说,这样item就具有出场动画效果。

除了使用xml也还可以通过LayoutAnimationController类实现。

{}Activity之间的切换效果

Activity有默认的切换效果,但是也可以自定义切换效果。

Activity切换效果主要用overridePendingTransition(),这个方法必须定义在startActivity()或者finish()之后调用才能生效。否则动画效果不起作用。

//比如Activity A跳转到Activity B,那么exitAnim效果在Activity A,enterAnim效果在Activity B  。

Activity对象.overridePendingTransition(int enterAnim, int exitAnim)

Fragment也可以添加切换动画,主要用FragmentTransaction对象的setCustomAnimations()来添加切换动画。

Activity之间的切换效果还可以给Activity设置样式(android:theme=”@style/….”)来实现,个人觉得用样式比调用方法更简单。

[]属性动画

属性动画可以对任何对象的属性进行动画而不仅仅是View,甚至还可以没有对象。属性动画的效果:在一个时间间隔内完成对象从一个属性值到另一个属性值的改变。只要对象有这个属性,它就能实现动画效果。属性动画的默认时间间隔是300ms。默认的帧率是10ms/帧。

属性动画是在API 11才出现,可以采用开源动画库NineOldAndroids(http://nineoldandroids.com)来兼容以前的版本。NineOldAndroids在API 11以前的版本底层还是采用View动画来实现。

比较常用的属性动画类:ValueAnimator,ObjectAnimator,AnimatorSet。ObjectAnimator继承ValueAnimator,AnimatorSet是动画集合。

属性动画既可以采用代码来实现,也可以采用xml来实现,xml文件存放到res/animator。建议采用代码来实现。因为代码来实现比较简单。更重要的原因是有时一个属性的起始值是无法提前确定的。

{}ObjectAnimator (< objectAnimator >)


android:repeatCount:动画的重复次数。默认值为0,其中 -1表示无限循环。

android:repeatMode:动画的重复模式。有2个值分别是:restart和reverse。其中restart表示连续重复。reverse表示逆向重复,逆向重复是指第一次顺着播放,第二次倒着播放,第三次顺着播放。

android:valueType:intType表示属性的类型为整型,floatType表示属性的类型为浮点型。如果属性的类型为颜色,可以不需要指定。系统会自动对颜色类型的属性做处理。

{}ValueAnimator (< animator >)


{}AnimatorSet (< set >)




android:ordering:子动画播放的顺序。有2个值分别是:together(默认值),sequentially。其中together表示动画集合中的子动画同时播放。sequentially表示动画集合中的子动画按照前后顺序依次播放。

{}xml格式的属性动画加载

Animator animator= AnimatorInflater.loadAnimator(this,R.animator.animator_text);
animator.setTarget(mButton);
animator.start();

{}属性动画的监听

Animator对象.addListener(AnimatorListener listener)

AnimatorListener 接口有四个方法:

void onAnimationStart(Animator animation); //动画开始
void onAnimationEnd(Animator animation); //动画结束
void onAnimationCancel(Animator animation); //动画取消
void onAnimationRepeat(Animator animation); //动画重复播放

ValueAnimator对象.addUpdateListener(AnimatorUpdateListener listener);

注意:动画被取消,onAnimationEnd()也会被调用。所以动画被取消时,会依次调用onAnimationCancel()–> onAnimationEnd()

AnimatorUpdateListener 接口有一个方法:

void onAnimationUpdate(ValueAnimator animation); 监听整个动画过程,动画是由每一帧组成的,每播放一帧就会被调用一次。

 ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {

        // 获取当前动画的进度值,1~100。为ofInt()中设定的值
        int currentValule = (int) animation.getAnimatedValue();

        // 获取动画当前时间流逝的百分比,范围在0~1之间
        float fraction = animation.getAnimatedFraction();
        ......
    }
});

{}代码实现属性动画

ObjectAnimator animator= ObjectAnimator.ofFloat(Object target, String propertyName, float... values);

ObjectAnimator animator= ObjectAnimator.ofInt(Object target, String propertyName, float... values);

ObjectAnimator animator= ObjectAnimator.ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values);

animator.start();

常用属性对应的字符串(propertyName)有:
1,translationX、translationY:控制view对象相对其左上角坐标在X、Y轴上偏移的距离。

2,rotation、rotationX、rotationY:控制view对象绕支点进行2D和3D旋转

3,scaleX、scaleY:控制view对象绕支点进行2D缩放。

4,pivotX、pivotY:控制view对象的支点位置,这个位置一般就是view对象的中心点。围绕这个支点可以进行旋转和缩放处理。

5,x、y:描述view对象在容器中的最终位置,是最初的左上角坐标和translationX、translationY值的累计和。

6,alpha:表示view对象的透明度。默认值是1(完全透明)、0(不透明)。

values对象有一个或多个属性值;当只指定一个属性值,系统默认此值为结束值;当指定两个属性值,系统默认分别为起始值和结束值;当指定三个或三个以上时,系统默认线性插值。

注:如果对象(target)的属性(propertyName)类型是整型调用ofInt(),如果是浮点型调用ofFloat()。不然可能会无效果。

{}AnimatorSet

AnimatorSet可以让多个动画配合执行,比如:多个动画同时进行,一个动画执行完再执行另一个动画。

AnimatorSet的方法:

playSequentially(Animator… items) //多个动画依次执行
playTogether(Animator… items) //多个动画同时执行
play(Animator anim) //返回AnimatorSet.Builder对象

AnimatorSet.Builder有四个方法:

after(Animator anim) //将现有动画插入到传入的动画之后执行
after(long delay) //将现有动画延迟指定毫秒后执行
before(Animator anim) //将现有动画插入到传入的动画之前执行
with(Animator anim) //将现有动画和传入的动画同时执行

{}PropertyValuesHolder

PropertyValuesHolder可以在同一个动画中改变多个属性,还可以通过设置Keyframe(关键帧),把同一个动画属性拆分成多个阶段。

//比如:改变透明度的同时改变尺寸
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 0, 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 0, 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 0, 1);

ValueAnimator valueAnimator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3);
valueAnimator.start();

//比如:初始帧progress为0,时间进行到一半progress为100,结束帧progress回落到80
Keyframe keyframe1= Keyframe.ofFloat(0, 0);
Keyframe keyframe2= Keyframe.ofFloat(0.5f, 100);
Keyframe keyframe3= Keyframe.ofFloat(1, 80);

PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);

ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolder);
objectAnimator.start();

{}ViewPropertyAnimator

ViewPropertyAnimator是Android 3.1增加的功能,View对象调用animate()返回的就是ViewPropertyAnimator对象。

ViewPropertyAnimator viewPropertyAnimator = View对象.animate();

注意:

()其中带By()后缀的是指改变多少,没有带后缀的是指改变为多少。比如:translationX(100) 表示把View的translationX值渐变为100,而translationXBy(100) 则表示把View的translationX值渐变地增加100。

()ViewPropertyAnimator只能做平移,旋转,缩放,透明度动画。

()ViewPropertyAnimator的使用

View对象.animate().
        translationX(float value).
        rotation(float value).
        scaleX(float value).
        alpha(float value).
        setDuration(long duration).
        setInterpolator(TimeInterpolator interpolator);

注意:

()ViewPropertyAnimator也可以设置时间(setDuration())和插值器(setInterpolator())

()start()可以默认不调用,因为使用隐式启动动画,但是动画不会立刻执行,而是ViewPropertyAnimator设置的方法都执行完毕后,动画才会自动启动。当然,也可以显示调用start()来启动动画

()ViewPropertyAnimator设置监听

//设置监听
ViewPropertyAnimator.setListener(new Animator.AnimatorListener(){
        //实现方法
})

ViewPropertyAnimator.setUpdateListener(new AnimatorUpdateListener(){
        //实现方法
})

//移除监听
ViewPropertyAnimator.setListener(null)
ViewPropertyAnimator.setUpdateListener(null)


ViewPropertyAnimator.withStartAction(Runnable runnable)
ViewPropertyAnimator.withEndAction(Runnable runnable)

注意:withStartAction() / withEndAction() 是一次性的,在动画执行结束后就自动弃掉了,就算之后再重用ViewPropertyAnimator来做别的动画,用它们设置的回调也不会再被调用。

{}插值器(Interpolator)和估值器(Evaluator)

时间插值器:根据时间流逝的百分比来计算出当前属性值改变的百分比。直接控制动画的变化速率,形象点说就是加速度,可以简单理解为变化的快慢。

常用的插值器LinearInterpolator(线性插值器:匀速动画),AccelerateDecelerateInterpolator(加速减速插值器,默认值),DecelerateInterpolator(减速插值器),AccelerateInterpolator(加速插值器),BounceInterpolator(弹跳值器,可以实现弹跳效果)。具体的插值器可以查看这个网址(http://hencoder.com/ui-1-6)

自定义插值器需要实现 TimeInterpolator 接口或者 Interpolator 接口,Interpolator 继承 TimeInterpolator。需要实现接口的getInterpolation(float input)。

input和fraction的关系:input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()中的,fraction就是getInterpolation()的返回值。

类型估值器:根据当前属性改变的百分比来计算改变后的属性值。系统定义的有IntEvaluator (针对整型属性),FloatEvaluator(针对浮点型属性),ArgbEvaluator(针对Color属性)。

自定义估值器需要实现TypeEvaluator接口,需要实现接口的evaluate()。如果是对其它类型(非int,Float,Color)做动画,那就必须要自定义类型估值算法。

插值器和估值器是实现非匀速动画的重要手段。

{}属性动画的原理

属性动画要求动画作用的的对象提供该属性的get和set方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,随着时间的推移,所传递的值越来越接近最终值。

{}属性动画的条件

1,属性动画作用的对象必须要提供属性的set…(),如果动画的时候没有传递初始值,那么还要提供get…(),因为系统要去获取属性的初始值。如果这个条件不满足,程序直接Crash。

2,属性动画作用的对象的set….()对属性所做的改变必须能够通过某种方法反映出来。比如会带来UI的改变之类。如果这个条件不满足,动画无效果但不会Crash。

{}针对属性动画条件的解决方法

1,给你的对象加上set…()和get…(),如果你有权限的话。

这种方式是最简单的,但是往往是不可行的。

2,用一个类来包装原始对象,间接为其提供set…()和get…()。

这种方式是比较常见的。

3,采用ValueAnimator,监听动画过程(addUpdateListener()),在动画过程中修改对象的属性值。

ValueAnimator本身不作用于任何对象,也就说直接使用它没有任何动画效果。它可以对一个值做动画,然后监听其动画过程,在动画过程中修改对象的属性值。

属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的,ValueAnimator对过渡动画值的计算依靠一个时间因子(fraction),而这个时间因子(fraction)是系统由setDuration()设置的动画执行时间通过计算得来的,所以ValueAnimator还负责管理动画的持续时间、播放次数、播放模式、以及对动画设置监听器等。

{}动画的注意点

1,View动画的问题

View动画是对View的影像做动画,并不是真正的改变View的状态。有时可能会出现动画完成后View无法隐藏的问题,即setVisibility(View.GONE)失效。这时只要View对象调用clearAnimation()清除View动画。

2,动画元素的交互

将View平移后,View动画新位置无法触发点击事件,但是老位置可以触发点击事件。3.0之后的属性动画新位置可以触发点击事件,老位置无法触发点击事件。3.0之前的属性动画新位置无法触发点击事件,但是老位置可以触发点击事件。这是因为3.0之前没有属性动画,所谓的属性动画其实底层是View动画来实现。

浅析Android动画系列的三篇文章:

View动画高级实例探究 (一)
http://www.cnblogs.com/wondertwo/p/5295976.html

属性动画与高级实例探究 (二)
http://www.cnblogs.com/wondertwo/p/5312482.html

自定义Interpolator与TypeEvaluator(三)
http://www.cnblogs.com/wondertwo/p/5327586.html

Android属性动画完全解析(上),初识属性动画的基本用法
http://blog.csdn.net/guolin_blog/article/details/43536355

Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
http://blog.csdn.net/guolin_blog/article/details/43816093

Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法
http://blog.csdn.net/guolin_blog/article/details/44171115

你可能感兴趣的:(读书笔记)