Android开发艺术探索 第7章 动画深入分析 读书笔记

Android动画可以分3种:View动画,帧动画和属性动画;属性动画为API11的新特性,在低版本是无法直接使用属性动画的。
本章主要学习内容:

  1. View动画以及自定义View动画。
  2. View动画的一些特殊使用场景。
  3. 对属性动画做了一个全面的介绍。
  4. 使用动画的一些注意事项。

7.1 View动画

  1. View动画的四种变换效果对应着Animation的四个子类:TranslateAnimation(平移动画)、ScaleAnimation(缩放动画)、RotateAnimation(旋转动画)和AlphaAnimation(透明度动画),他们即可以用代码来动态创建也可以用XML来定义,推荐使用可读性更好的XML来定义。
  2. <set>标签表示动画集合,对应AnimationSet类,它可以包含若干个动画,并且他的内部也可以嵌套其他动画集合。android:interpolator 表示动画集合所采用的插值器,插值器影响动画速度,比如非匀速动画就需要通过插值器来控制动画的播放过程。
    android:shareInterpolator表示集合中的动画是否和集合共享同一个插值器,如果集合不指定插值器,那么子动画就需要单独指定所需的插值器或默认值。
  3. Animation通过setAnimationListener方法可以给View动画添加过程监听。
  4. 自定义View动画只需要继承Animation这个抽象类,并重写initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中进行相应的矩形变换,很多时候需要采用Camera来简化矩形变换过程。
  5. 帧动画是顺序播放一组预先定义好的图片,类似电影播放;使用简单但容易引发OOM,尽量避免使用过多尺寸较大的图片。

7.2 View动画的特殊使用场景

  1. LayoutAnimation作用于ViewGroup,为ViewGroup指定一个动画,当他的子元素出场的时候都会具有这种动画,ListView上用的多,LayoutAnimation也是一个View动画。
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animationOrder="normal"
    android:delay="0.3" android:animation="@anim/anim_item"/>
//--- delay 表示动画开始的时间延迟,比如子元素入场动画的时间周期为300ms,
//那么0.5表示每个子元素都需要延迟150ms才开始播放入场动画。
//--- animationOrder 表示子元素的动画的顺序,有三种选项:
//normal(顺序显示)、reverse(逆序显示)和random(随机显示)。
//---1. android:animation 为子元素指定具体的入场动画
//----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:shareInterpolator="true">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
    <translate
        android:fromXDelta="300"
        android:toXDelta="0" />
</set>

使用LayoutAnimation

//--- 第一种方法、为需要的ViewGroup指定android:layoutAnimation属性
//---这样ViewGroup的子View就有出场动画了
   <ListView
       android:id="@+id/lv"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       android:layoutAnimation="@anim/anim_layout"/>
//
//--- 第二种方法、通过LayoutAnimationController来实现
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listview.setLayoutAnimation(controller);
  1. Activity/Fragment的切换效果
    在startActivity(Intent)或finish()之后调用overridePendingTransition(int enterAnim,int exitAnim)方法。
    Fragment也可以添加切换动画,通过FragmentTransaction中的
    setCustomAnimations()方法来添加;需考虑兼容性使用View动画,属性动画是API11新引入的;

7.3属性动画

  1. 属性动画可以对任意对象的属性进行动画而不仅仅是View,动画默认间隔300ms,默认帧率10ms/帧。在一个时间间隔内完成对象从一个属性值到另一个属性值的改变。
  2. android:propertyName 表示属性动画的作用的属性的名称 。
    android:duration 表示动画的时长。
    android:valueFrom 表示动画的起始值。
    android:valueTo 表示属性的结束值。
    android:startOffset 表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才会真正播放此动画。
    android:repeatCount 表示动画的重复次数(默认为0,其中-1表示无线循环)。
    android:repeatMode 表示动画的重复模式 (repeat和reverse可选,表示连续重复和逆向重复(第一次播放完之后,第二次倒着播,第三次重头开始播,第四次倒着播))。
    android:valueType 表示android:propertyName所指定的属性的类型,可选intType/floatType;
    如果android:propertyName指定的属性表示颜色,则不需要指定该属性。
  3. 实际开发中建议使用代码来实现属性动画,代码来实现比较简单,而且很多时候一个熟悉的初始值无法提前知道,需在代码中动态获取。
7.3.2 理解插值器和估值器
  1. 时间插值器(TimeInterpolator)的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画),AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢中间快),DecelerateInterpolator(减速插值器:动画越来越慢)。
  2. 估值器(TypeEvaluator)的作用是根据当前属性改变的百分比来计算改变后的属性值。系统预置有IntEvaluator 、FloatEvaluator 、ArgbEvaluator。
//整形估值器源码
 /**
    * @param fraction   表示开始和结束值之间的比例
    * @param startValue  开始值         
    * @param endValue  结束值
    * @return  
    */
public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}
  1. 插值器和估值器除了系统提供之外,我们还可以自定义。自定义插值器需要实现Interpolator或者TimeInterpolator;自定义估值器算法需要实现TypeEvaluator。
7.3.3属性动画的监听器
public static interface AnimatorListener {
    void onAnimationStart(Animator animation); //动画开始
    void onAnimationEnd(Animator animation); //动画结束
    void onAnimationCancel(Animator animation); //动画取消
    void onAnimationRepeat(Animator animation); //动画重复播放
}
  1. 为了方便开发,系统提供了AnimatorListenerAdapter类,它是AnimatorListener的适配器类,可以有选择的实现以上4个方法。
  2. AnimatorUpdateListener会监听整个动画的过程,动画由许多帧组成的,每播放一帧,onAnimationUpdate就会调用一次。
7.3.4 对任意属性做动画
  1. 属性动画要求作用的对象提供该属性的get和set方法,缺一不可。
  2. 如果你的对象没有对应的get和set方法
  • 请给你的对象加上get和set方法,如果你有权限的话(如果直接使用系统的类,是无法加上的);
  • 用一个类来包装原始对象,间接为其提供get和set方法;
//包装View类 用于给属性动画调用 从而包装了set get
public class ViewWrapper {
      private View target;
      public ViewWrapper(View target) {
          this.target = target;
      }
      public int getWidth() {
          return target.getLayoutParams().width;
      }
      public void setWidth(int width) {
          target.getLayoutParams().width = width;
          target.requestLayout();
      }
}
  • 采用ValueAnimator,监听动画过程,自己实现属性的改变;
   /** 使用ValueAnimator 监听动画过程 自己实现属性改变
     *
     * @param target 作用的View
     * @param start 动画起始值
     * @param end 动画终止值
     */
    private void startValueAnimator(final View target, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            private IntEvaluator mEvaluation = new IntEvaluator();//新建一个整形估值起 方便估值使用

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获得当前动画的进度值 1~100之间
                int currentValue = (int) animation.getAnimatedValue();
                Log.e("Anim", "currentValue: " + currentValue);
                //获得当前进度占整个动画过程的比例,浮点型,0~1之间
                float fraction = animation.getAnimatedFraction();
                //调用估值器,通过比例计算出宽度 ,再设置给Button
                int targetWidth = mEvaluation.evaluate(fraction, start, end);
                target.getLayoutParams().width = targetWidth;
                target.requestLayout();
            }
        });
    }

7.3.5 属性动画的工作原理

通过反射调用get/set方法;属性动画需要运行在有Looper的线程中。


7.4 使用动画的注意事项

  1. 使用帧动画时,当图片数量较多且图片分辨率较大的时候容易出现OOM,需注意,尽量避免使用帧动画。
  2. 使用无限循环的属性动画时,在Activity退出时及时停止,否则将导致Activity无法释放从而造成内存泄露
  3. View动画是对View的影像做动画,并不是真正的改变了View的状态,因此有时候会出现动画完成后View无法隐藏(setVisibility(View.GONE)失效),这时候调用view.clearAnimation()清理View动画即可解决。
  4. 不要使用px,使用px会导致不同设备上有不同的效果。
  5. View动画是对View的影像做动画,View的真实位置没有变动,也就导致点击View动画后的位置触摸事件不会响应,属性动画不存在这个问题。
  6. 使用动画的过程中,使用硬件加速可以提高动画的流畅度。
  7. 动画在3.0以下的系统存在兼容性问题,特殊场景可能无法正常工作,需做好适配工作。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,697评论 0 10
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 提及农村,在我们的第一印象中是这样的 孩子的重点在玩和帮父母干家务 他们的快乐很简单,父母很多时间是在外打工,他们...
    冷_9825阅读 407评论 2 1
  • “安生啊,你说这村口的王大妈都等了她男人三年了她男人也没回来,我看啊,她男人怕是回不来咯。” 安生扬了扬眉头,但是...
    导演i求平台阅读 130评论 0 0
  • 若苦能诉 尚还可撑 若难能助 尚还可解 一个人 独当一面 远在天涯 从最初的无措 到现今的自如 中间滋味 唯有自知 好在
    负零小子阅读 143评论 0 0