Android动画分析(一)

Android 动画种类

  • View Animation: 视图动画(Tween(补间)动画),只能被用来设置View的动画。

  • Drawable Animation: 帧动画(也叫 Frame 动画)其实可以划分到视图动画的类别,专门用来一个一个的显示 Drawable 的resources,就像放幻灯片一样。

  • Property Animation: 属性动画只对 Android 3.0(API 11)以上版本的Android 系统才有效,这种动画可以设置给任何 Object,包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的,可以让你自定义任何类型和属性的动画。

1. View Animation 视图动画使用解析

    1. 视图动画特点

      • 视图动画可以在一个视图容器内执行一系列简单变换(平移、缩放、旋转、透明度)
      • 视图动画通过XML 或 Android 代码定义,建议使用 XML 文件定义,因为它更具可读性、可重用性。
    1. 动画属性
xml属性 java 方法 解释
android:detachWallpaper setDetachWallpaper(boolean) 是否在壁纸上运行
android:duration setDuration(long) 动画持续时间,毫秒为单位
android:fillAfter setFillAfter(boolean) 控件动画结束时是否保持动画最后的状态
android:fillBefore setFillBefore(boolean) 控件动画结束时是否还原到开始动画前的状态
android:fillEnabled setFillEnabled(boolean) 与android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 设定插值器(指定的动画效果,譬如回弹等)
android:repeatCount setRepeatCount(int) 重复次数
android:repeatMode setRepeatMode(int) 重复类型有两个值,reverse表示倒序回放,restart表示从头播放
android:startOffset setStartOffset(long) 调用start函数之后等待开始运行的时间,单位为毫秒
android:zAdjustment setZAdjustment(int) 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal

2-1 Alpha属性详解

xml属性 java方法 解释
android:fromAlpha AlphaAnimation(float fromAlpha, …) 动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)
android:toAlpha AlphaAnimation(…, float toAlpha) 动画结束的透明度,同上

2-2 Rotate属性详解

xml属性 java方法 解释
android:fromDegrees RotateAnimation(float fromDegrees, …) 旋转开始角度,正代表顺时针度数,负代表逆时针度数
android:toDegrees RotateAnimation(…, float toDegrees, …) 旋转结束角度,正代表顺时针度数,负代表逆时针度数
android:pivotX RotateAnimation(…, float pivotX, …) 缩放起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
android:pivotY RotateAnimation(…, float pivotY) 缩放起点Y坐标,同上规律

2-3 Scale属性详解

xml属性 java方法 解释
android:fromXScale ScaleAnimation(float fromX, …) 初始X轴缩放比例,1.0表示无变化
android:toXScale ScaleAnimation(…, float toX, …) 结束X轴缩放比例
android:fromYScale ScaleAnimation(…, float fromY, …) 初始Y轴缩放比例
android:toYScale ScaleAnimation(…, float toY, …) 结束Y轴缩放比例
android:pivotX ScaleAnimation(…, float pivotX, …) 缩放起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
android:pivotY ScaleAnimation(…, float pivotY) 缩放起点Y轴坐标,同上规律

2-4 Translate属性详解

xml属性 java方法 解释
android:fromXDelta TranslateAnimation(float fromXDelta, …) 起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)
android:toXDelta TranslateAnimation(…, float toXDelta, …) 结束点X轴坐标,同上规律
android:fromYDelta TranslateAnimation(…, float fromYDelta, …) 起始点Y轴从标,同上规律
android:toYDelta TranslateAnimation(…, float toYDelta) 结束点Y轴坐标,同上规律

2-5 AnimationSet详解
AnimationSet 继承自 Animation,是上面四种的组合容器管理类,没有自己特有的属性,他的属性也继承自 Animation 。所以特别注意,当我们对set标签使用 Animation 的属性时会对该标签下的所有子控件都产生影响。

2-6 View Animation 使用实例

  • xml 使用实例
    R.anim 目录下新建一个动画 xml文件。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
     android:shareInterpolator="true"
    android:duration="3000"
    android:fillAfter="true">

    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.3" />

    <scale
        android:fromXScale="1"
        android:toXScale="0.5"
        android:fromYScale="1"
        android:toYScale="0.5"
        android:pivotX="100"
        android:pivotY="50%" />

    <translate
        android:fromXDelta="0"
        android:toXDelta="20%p"
        android:fromYDelta="0"
        android:toYDelta="20%p" />

    <rotate
        android:fromDegrees="0"
        android:toDegrees="15"
        android:pivotX="0"
        android:pivotY="0" />
</set>

java代码中使用:

ImageView image= (ImageView) findViewById(R.id.image);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.view_animation);
image.startAnimation(animation);

2-7 Animation 比较实用的方法介绍:

Animation类的方法 解释
reset() 重置Animation的初始化
cancel() 取消Animation动画
start() 开始Animation动画
setAnimationListener(AnimationListener listener) 给当前Animation设置动画监听
hasStarted() 判断当前Animation是否开始
hasEnded() 判断当前Animation是否结束

2-8 View 中和视图动画相关的几个常用方法:

View类的常用动画操作方法 解释
startAnimation(Animation animation) 对当前 View 开始设置的Animation 动画
clearAnimation() 取消当前 View 在执行的 Animation 动画

2-9 视图动画需要注意的地方

  • 视图动画执行完之后并未改变 View 的真实布局属性值。

切记这一点,譬如我们在 Activity 中有一个 Button 在屏幕上方,我们设置了平移动画移动到屏幕下方,然后保持动画最后执行状态,看起来 Button
是在屏幕下方,但是这时点击屏幕下方动画执行之后的 Button,Button 是没有任何反应的,而点击原来屏幕上方原来是 Button 的地方却能响应点击Button的事件。这可以说是视图动画的一个 bug 。

2-10 视图动画插值器 Interpolator

  • Android 的各种插值器都实现了Interpolator接口,系统提供的插值器具体如下:
java类 xml id值 描述
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 动画始末速率较慢,中间加速
AccelerateInterpolator @android:anim/accelerate_interpolator 动画开始速率较慢,之后慢慢加速
AnticipateInterpolator @android:anim/anticipate_interpolator 开始的时候从后向前甩
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 类似上面AnticipateInterpolator
BounceInterpolator @android:anim/bounce_interpolator 动画结束时弹起
CycleInterpolator @android:anim/cycle_interpolator 循环播放速率改变为正弦曲线
DecelerateInterpolator @android:anim/decelerate_interpolator 动画开始快然后慢
LinearInterpolator @android:anim/linear_interpolator 动画匀速改变
OvershootInterpolator @android:anim/overshoot_interpolator 向前弹出一定值之后回到原来位置
PathInterpolator 新增,定义路径坐标后按照路径坐标来跑。
  • 插值器使用方法:
    在 res/anim/ 目录下创建 my_Interpolator.xml 插值器文件。r如下:
<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
    android:attribute_name="value"
    />

在视图动画文件中引用自定义的或者系统提供的。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/accelerate_decelerate_interpolato"
     android:shareInterpolator="true"
     android:duration="3000"
    android:fillAfter="true">

    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.3" />

    <scale
        android:fromXScale="1"
        android:toXScale="0.5"
        android:fromYScale="1"
        android:toYScale="0.5"
        android:pivotX="20%"
        android:pivotY="50%p" />
</set>

2. Drawable Animation(Drawable动画)使用详解

  • Drawable 动画其实就是 Frame 动画(帧动画),它允许你实现像播放幻灯片一样的效果,这种动画的实质其实是 Drawable,所以这种动画的XML 定义方式文件一般放在 res/drawable/ 目录下。

  • Drawable动画详细说明

    我们依旧可以使用 xml 或者 java 方式实现帧动画。但是依旧推荐使用xml,具体如下:

    <animation-list> 必须是根节点,包含一个或者多个 <item> 元素,属性有:
    android:oneshot true 代表只执行一次,false 循环执行。
    <item> 类似一帧的动画资源。

    <item> animation-list 的子项,包含属性如下:
    android:drawable:一个 frame 的 Drawable 资源。
    android:duration :一个 frame 显示多长时间。

举个栗子:

<!-- 注意:rocket.xml文件位于res/drawable/目录下 -->
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true"  >
    <item
        android:drawable="@[package:]drawable/drawable_resource_name"
        android:duration="integer" />
</animation-list>

在 java 代码中调用:

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();

PS 注意的地方:
AnimationDrawable.start() 方法不能在 Activity 的 onCreate 方法中调运,因为 AnimationDrawable 还未完全附着到 window 上,所以最好的调运时机是 onWindowFocusChanged() 方法中。

3. Property Animation(属性动画)使用详解

上文说了视图动画最大的缺陷就是改变的只是显示,并不能显示响应事件。因此,Android 在 3.0 后推出 Property Animation(属性动画)来解决这个问题。

在属性动画中,使用的最多情况就是:AnimatorSetObjectAnimator 搭配。使用一个 ObjectAnimator 可以控制对象的一个属性,而使用多个 ObjectAnimator 就可以控制对象的多个属性,组合到 AnimatorSet 就组成了动画。

属性动画很重要的一点就是:属性动画通过调用属性的 getset 方法来真实控制一个View的属性值,因此可以响应事件。

3-1 ObjectAnimator

  • ObjectAnimator 是属性动画框架中最重要的实行类。创建一个 ObjectAnimator对象通过它的静态方法就可以了。

举个栗子

ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationX",300);
animator.setDuration(3000);
animator.start();

该静态方法的第一个参数是要操纵的View,第二个是要操纵的属性,第三个是一个可变的数组参数,也可以是一个值,一个值表示变化到此值

  • ObjectAnimator要操纵的属性必须具有 getset 方法,不然 ObjectAnimator 不会生效,常见的可以操纵的属性如下:
  1. translationXtranslationY:这两个属性作为一种增量来控制着 View 对象从它布局容器的左上角坐标偏移的位置。

  2. rotationrotationXrotationY:这三个属性控制 View 对象围绕支点进行 2D 和 3D 旋转。

  3. scaleXscaleY:控制 View 对象围绕它的支点进行 2D 缩放。

  4. pivotXpivotY:控制 View 对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下,支点就是该 View 的中心点。

  5. xy:这两个属性是 View 对象在它的容器中的最终位置,是最初的左上角的 translationXtranslationY 值得累计和。

  6. alpha:View 的透明度。1 为不透明,0 为全透明。

3-2 PropertyValuesHolder
类似视图动画的 AnimationSet,在属性动画中,如果针对同一个对象的多个属性,要同时作用多种动画,可以使用 PropertyValuesHolder 来实现。

举个栗子

//平移的同时改变X,Y轴的缩放
PropertyValuesHolder pv1 = PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder pv2 = PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuesHolder pv3 = PropertyValuesHolder.ofFloat("scaleY",1f,0,1f);

ObjectAnimator.ofPropertyValuesHolder(imageView,pv1,pv2,pv3).setDuration(3000).start();

3-3 ValueAnimatior
ValueAnimatior 本身不提供任何动画效果,它更像一个数值发生器,用来产生具有一定规律的数字,从而让调用者控制动画的实现过程。

举个栗子

ValueAnimator animator = ValueAnimator.ofInt(0,1000);
animator.setTarget(imageView);
animator.setDuration(3000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (Integer)animation.getAnimatedValue();
               //使用这个 value 改变 View 的状态
                ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
                layoutParams.height = value;
                imageView.setLayoutParams(layoutParams);
            }
        });

3-4 AnimationSet
AnimationSet 能对同一个对象的多个属性同时进行动画效果,还能实现精确的顺序控制,这点比 PropertyValuesHolder更灵活。

举个栗子

AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"translationX",300);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView,"translationY",300);
animatorSet.setDuration(3000);
animatorSet.play(animator).after(animator1);
animatorSet.start();

在属性动画中,AnimationSet 通过 playTogether()(同时播放)、playSequentially()(顺序播放)、animatorSet.play().with()(同时播放)、animatorSet.play().before()(先 play()before())、animatorSet.play().after()(先 after()play() )这些方法来控制多个动画的协同工作方式,从而控制动画的播放顺序。

3-4 属性动画的事件监听
一个完整的动画具有 StartRepeatEndCancel 四个过程,我们可以很方便地监听其中一个或者几个事件。

举个栗子

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"translationX",300);
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) {

            }
        });

或者监听其中一个事件:

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"translationX",300);

animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });

3-5 在XML中使用属性动画
属性动画和视图动画一样,可以直接写在 XML 中,通过 AnimatorInflater.loadAnimator(context,res) 使用。

举个栗子
在 res 目录下新建一个 animator 目录(注意不能是 anim),然后写 XML 文件。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="2000"
     android:ordering="sequentially"><!--动画执行顺序 sequentially:顺序执行;together:同时执行。 -->

    <objectAnimator
        android:propertyName="translationX"
        android:valueFrom="0"
        android:valueTo="200"
        android:valueType="floatType" />

    <set android:ordering="together">
        <objectAnimator
            android:propertyName="scaleX"
            android:valueFrom="1"
            android:valueTo="0.5"
            android:valueType="floatType" />
        <objectAnimator
            android:propertyName="translationY"
            android:valueFrom="0"
            android:valueTo="450"
            android:valueType="floatType" /><!--动画值的类型-->
    </set>
    
</set>

在代码中引用:

Animator animator = AnimatorInflater.loadAnimator(this,R.animator.object_animation);
animator.setTarget(imageView);
animator.start();

4. 总结

动画在安卓中使用的非常普遍,是当地使用动画能增添程序的趣味性。本篇介绍了安卓常见的动画的用法,下一篇介绍如何自定义动画。

参考资料

Android应用开发之所有动画使用详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,580评论 0 9
  • 转载一篇高质量博文,原地址请戳这里转载下来方便今后查看。1 背景不能只分析源码呀,分析的同时也要整理归纳基础知识,...
    Elder阅读 1,899评论 0 24
  • 从前种种,譬如昨日死;今日种种,譬如今日生。
    我爱吃鱼吃火锅阅读 138评论 0 0
  • 「为什么知道了很多道理,却还是过不好这一生?」 都记得在《后会无期》里的这句台词吧,读了很多书,知道某些道理,便以...
    沐森读书阅读 407评论 0 0