该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!


前言

上一篇文章呢,我们说了关于View动画的那些事,这里也在总结一下,使用View动画时需要注意以下4点:(更多详情请参看我的上一篇博客。)

  1. View动画的坐标系:View动画说到底是View的一系列运动,既然是运动,那么参照物(坐标系)是很重要的。
  2. View动画的使用场景:View动画的主体是View,更准确的说是View的副本(影子),View动画更改的只是显示,其x,y坐标仍然没有改变,响应事件的位置没有改变,也就是说view本身并没有改变。也因此,不要使用View动画做交互性操作,例如点击。
  3. 自定义View动画的步骤:如果我们不满足于系统已经定义好的Animation,=,可以自定义自己的Animation,重写initializeapplyTransformation这两个方法即可。
  4. Matrix:接着上一点说,如果想要掌握高级的酷炫的动画效果,那么理解Android View动画的矩阵变换的实质是必经之路。

那么本章呢是来介绍Android动画的另外一个大类属性动画

属性动画简介

 属性动画是API11新加入的特性,和View动画不同,它可以对任何对象做动画,甚至还可以没有对象,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对对象从一个属性值到另一个属性值得改变。常用属性动画类ValueAnimator、ObjectAnimator和AnimationSet,其中ObjectAnimator继承于ValueAnimator.

 

注:gihub上JakeWharton大神对API11之前做了属性动画的兼容,它的原理其实也很简单,主要就是判断当前sdk版本,如果大于API11,那么就调用官方的API,否则自己实现动画效果。另外,在API使用方面,它与官方的属性动画基本一致。另外,在API使用方面,它与官方的属性动画基本一致。比如ObjectAnimator、ValueAnimator等等。 感兴趣的同学可以访问该项目的github网址NineOldAndroids

属性动画的使用

Java代码实现

例如改变一个对象(obj)的translationY属性,可以写为

  1. ValueAnimator.ofFloat(obj,"translationY",100);

XML实现(属性动画的XML描述语法的固定格式)

  1. <set xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:ordering=["sequentially"|"together"]>
  3. <objectAnimator
  4. android:propertyName="string"
  5. android:duration="int"
  6. android:valueFrom="float|int|color"
  7. android:valueTo="float|int|color"
  8. android:startOffset="int"
  9. android:repeatCount="int"
  10. android:repeatMode=["restart"|"reverse"]
  11. android:valueType=["colorType"|"intType"]>
  12. </objectAnimator>
  13. <animator
  14. android:duration="int"
  15. android:valueFrom="float|int|color"
  16. android:valueTo="float|int|color"
  17. android:startOffset="int"
  18. android:repeatCount="int"
  19. android:repeatMode=["restart"|"reverse"]
  20. android:valueType=["colorType"|"intType"]>
  21. </animator>
  22. ...
  23. </set>

很多属性都是见名知义的,下面呢简单介绍一下各属性名称的含义。

属性动画的核心类有3个类,AnimatorSet,ObjectAnimator以及ValueAnimator

  1. XML文件中的 <set>标签对应AnimatorSet, <set>标签的ordering属性有2个候选值"sequentially"|"together",分别表示 <set>标签内的动画是按照前后顺序播放和同时播放。
  2. <animatior>对应ValueAnimator,

    android:duration:表示动画的时长

    android:valueFrom:表示属性的起始值

    android:valueTo:表示属性的结束值

    android:startOffset:表示动画的延迟时间,动画开始后,需要延迟多少毫秒后才会真正播放该动画

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

    android:repeatMode:表示动画的重复播放模式,restart表示动画每次都是重新开始播放,reverse表示动画第1 次播放完毕后,第2次会逆向播放,第3次又从头开始播放,以此类推
  3. <objectAnimator>对应ObjectAnimator,

    android:propertyName:表示属性动画作用对象的属性名称

    android:valueType:表示android:propertyName的值的类型,分为intType,和floatType,分别代表整型数值和浮点型数值,若android:propertyName指定的属性表示的是颜色,那么无需指定android:valueType,系统会自动适配

    其他属性的含义与上面的<animatior>一致。

属性动画的进阶

我们先来看一个需求:要求对一个Button做动画,要求让其宽度从原始宽度增加到500px。这也太简单了,

  1. Button mButton = (Button) findViewById(R.id.button);
  2. ObjectAnimator.ofInt(mButton,"width",500).setDuration(1000).start();

程序运行,但是却没有效果,这是为什么呢,仔细想想没效果也是应该的,因为你随便传递了一个属性名称过去,轻则动画没有效果,重则直接Crash。那么这个号称可以对任意属性做动画的属性动画使用的时候有哪些需要注意的地方呢

  1. 属性动画要求动画的作用对象提供该属性的get和set方法,
  2. 属性的改变必须通过某种方法反映出来,比如会带来UI的修改之类的

以上的条件缺一不可

这时又有一个问题如果想要对一个对象的属性做动画,但是属性又没有对应的get和set方法怎么办呢??

概括来讲有如下3种解决办法:

  1. 给你的对象加上get和set方法,如果你有权限的话。而这个方法对于Android SDK内部实现的类就不可行,这个方法是最简单的,但是往往是不可行的。
  2. 用一个类包装原始对象,间接为其提供get和set方法
  3. 采用ValueAnimator,监听动画过程,自己实现属性的改变

下面仍以上面Button的宽度动画作为需求给出方法2,3的解决代码

方法2:

  1. mButton = (Button) findViewById(R.id.button);
  2. ObjectAnimator.ofInt(new ViewWrapper(mButton),"width",500).setDuration(1000).start();
  3. private class ViewWrapper{
  4. private View mTarget;
  5. public ViewWrapper(View mTarget) {
  6. this.mTarget = mTarget;
  7. }
  8. public int getWidth() {
  9. return mTarget.getLayoutParams().width;
  10. }
  11. public void setWidth(int width) {
  12. mTarget.getLayoutParams().width = width;
  13. mTarget.requestLayout();
  14. }
  15. }

方法3:

使用方法3之前,我们先来看属性动画的监听器AnimatorUpdateListener和AnimatorListener

属性动画的监听器AnimatorUpdateListener和AnimatorListener

AnimatorUpdateListener

  1. public static interface AnimatorListener {
  2. void onAnimationStart(Animator animation);
  3. void onAnimationEnd(Animator animation);
  4. void onAnimationCancel(Animator animation);
  5. void onAnimationRepeat(Animator animation);
  6. }

如上代码所示AnimatorListener监听了动画的开始、结束、取消和重复播放,同时系统提供了AnimatorListenerAdapter适配器方便我们使用,我们可以继承这个类并有选择的实现方法。

AnimatorListener

  1. public static interface AnimatorUpdateListener {
  2. /**
  3. * <p>Notifies the occurrence of another frame of the animation.</p>
  4. *
  5. * @param animation The animation which was repeated.
  6. */
  7. void onAnimationUpdate(ValueAnimator animation);
  8. }

如上图所示,AnimatorUpdateListener 监听了动画的整个过程,动画每播放一帧,onAnimationUpdate就被调用一次,

下面就来看一下如何使用上面的属性动画的监听器来实现属性动画

  1. mButton = (Button) findViewById(R.id.button);
  2. performAnimate(mButton, mButton.getWidth(), 500);
  3. private void performAnimate(final View target, final int start, final int end) {
  4. ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
  5. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  6. // 持有一个IntEvaluator对象,方便下面估值的时候使用
  7. private IntEvaluator mEvaluator = new IntEvaluator();
  8. @Override
  9. public void onAnimationUpdate(ValueAnimator animator) {
  10. // 获得当前动画的进度值,整型,1-100之间
  11. int currentValue = (Integer) animator.getAnimatedValue();
  12. Log.d(TAG, "current value: " + currentValue);
  13. // 获得当前进度占整个动画过程的比例,浮点型,0-1之间
  14. float fraction = animator.getAnimatedFraction();
  15. // 直接调用整型估值器通过比例计算出宽度,然后再设给Button
  16. target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
  17. target.requestLayout();
  18. }
  19. });
  20. valueAnimator.setDuration(5000).start();
  21. }

使用动画的注意事项

  1. OOM问题,此类问题主要出现在帧动画中,帧动画中如果使用大量图片,则可能会造成OOM问题,避免的方法同理,最好不要在帧动画中使用大量大尺寸的图片
  2. View动画的问题,View动画的作用主题实际上是View的影子,所以View动画不适合做有交互性点击的动画,另外View动画也不能真正改变View的状态,所以有的时候会出现动画结束后,View.setVisibily(VIEW.GONE)失效,或者其他异常情况,使用View.clearAnimation()清除动画即可
  3. 内存泄露,在属性动画中有一类无限循环的动画,这类动画要在Activity销毁之前及时停止,否则会造成Activity无法回收导致内存泄漏。

本篇总结

本章呢接着上一篇说了Android动画的另外一个大类属性动画,至此Android动画相关的文章完结,因笔者水平有限,所以有不当之处还请指出


下篇预告

下篇呢,开始Android并发编程系列


参考博文


此致,敬礼

Android开发之漫漫长途 XVII——动画(续)的更多相关文章

  1. Android开发之漫漫长途 XVII——动画

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  2. Android开发之漫漫长途 XIV——RecyclerView

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  3. Android开发之漫漫长途 XV——RecyclerView

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  4. Android开发之漫漫长途 Ⅰ——Android系统的创世之初以及Activity的生命周期

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>中的相关知识,再次表示该书 ...

  5. Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(2)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  6. Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(1)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  7. Android开发之漫漫长途 Ⅳ——Activity的显示之ViewRootImpl初探

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  8. Android开发之漫漫长途 Ⅴ——Activity的显示之ViewRootImpl的PreMeasure、WindowLayout、EndMeasure、Layout、Draw

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  9. Android开发之漫漫长途 番外篇——自定义View的各种姿势1

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

随机推荐

  1. [leetcode]297. Serialize and Deserialize Binary Tree 序列化与反序列化二叉树

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  2. [leetcode]31. Next Permutation下一个排列

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  3. Centos6.5搭建vsftpd,并配置用户和密码登录

    Centos6.5搭建vsftpd,并配置用户和密码登录 2017年05月11日 18:40:47 阅读数:6142 1)安装vsftpd yum install vsftpd 2)配置vsftpd配 ...

  4. PHP常见的一些问题总结(收藏)

    本篇文章给大家带来的内容是关于PHP常见的一些问题总结(收藏),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1. 字符串定义的时候单引号和双引号有什么区别? 单引号加载速度比双引号 ...

  5. sql2012包含数据库,快速生成用户tsql脚本

    今天太忙(下班时,发现一个考试网站的不算BUG的BUG,这个BUG刚好能让我找到想要的数据,现在正辛苦的编码中...) 不多说,今天的技术文章,简单一点,帖一段昨天写的SQL代码 用于SQL2012中 ...

  6. I/O dempo

    标准读取写入 package io_stream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; i ...

  7. Chapter3_操作符_直接常量和指数计数法

    (1)直接常量 在程序中使用直接常量,相当于指导编译器,告诉它要生成什么样的类型,这样就不会产生模棱两可的情况.比如flaot a = 1f等,后缀表示告诉编译器想生成的类型.常用的后缀有l/L(lo ...

  8. C#部分试题实例

    1.在C#中,下列选项中自定义方法的语句错误的是().(选择一项) 正确答案:AD 解析:本题考查自定义方法的定义及调用.A项void是无返回值类型,D项定义方法的时候没有写返回值类型:故选AD. 2 ...

  9. Django的学习进阶(一)—— 外键的使用

    一.描述 在利用django做网络开发的时候我们会遇到一个问题就是,我们建立了多张数据表,但是多张数据表中的内容是不一样的,但是之间有着联系比如: 我有两张表,一张是记录歌曲信息的内容,一张是对歌曲操 ...

  10. Linux 第八天

    4.源码包和rpm包的区别 1)区别 安装前:概念上的区别 安装后:安装位置不同 2)安装位置 rpm包安装位置 Rpm包默认安装路径 /etc/ 配置文件安装目录 /usr/bin/ 可执行的命令安 ...