Android 动画详解

  android中酷炫的效果,都离不开动画的支持。这里我们详细介绍一下android中动画的分类。android的中动画分为帧动画、补间动画、属性动画。原理各不相同,实现的效果也大不相同。下面一一讲解三种动画。

帧动画

  帧动画顾名思义就是通过顺序一帧一帧播放图片从而产生动画效果,效果类似放电影。该动画缺点比较明显,就是如果图片过大过多会导致OOM。帧动画xml文件放置在drawable目录下而非anim文件夹下。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@drawable/ic_launcher_background"
        android:duration="150" />
    <item
        android:drawable="@drawable/ic_launcher_background"
        android:duration="150" />
</animation-list>

补间动画

  补间动画是通过对view进行旋转、缩放、渐变、透明度变化,而达到的一种动画效果。是一种渐进式动画。并且可以通过组合以上四种操作,完成复杂的自定义动画效果。缺点就是只是改变的view的展示状态,但是不会改变view的位置。例如我们将一个button通过位移想左移动100dp,然后停留在终点。但是我们可以发现展示的位置button点击无效果,不可以交互。而在button原始位置空白的地方点击会触发button的点击效果。也就是button本质还是在原来位置,只是展示左移了100dp。

属性说明

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="4000"
    android:fillAfter="true"
    android:fillBefore="true"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:repeatMode="restart | reverse"
    android:repeatCount = “0”
    android:shareInterpolator="true"
    android:startOffset="float">
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:fromYScale="float"
        android:pivotX="float"
        android:pivotY="float"
        android:toXScale="float"
        android:toYScale="float" />
    <rotate
        android:fromDegrees="float"
        android:pivotX="float"
        android:pivotY="float"
        android:toDegrees="float" />
    <translate
        android:fromXDelta="float"
        android:fromYDelta="float"
        android:toXDelta="float"
        android:toYDelta="float" />
</set>
通用属性说明:
  • android:duration=""动画时长,单位毫秒
  • android:fillAfter="true"动画完成后是否停留在结束位置,默认false
  • android:fillBefore="true"动画完成后是否停留在起点位置。默认true,优先级低于fillAfter
  • android:interpolator为动画的变化速度【可以单独设置,可以直接放在set里面】
      可以设置多种速度变化方式,这里只列出匀速、加速、减速
      匀速 @android:anim/linear_interpolator
      加速 @android:anim/accelerate_interppolator
      减速 @android:anim/decelerate_interpolator
  • android:repeatMode="restart | reverse"动画重复策略 restart从起点位置(正序)重复,reverse从结束位置(倒序)重复
  • android:repeatCount = “0”重复次数 “infinite”为无线重复
  • android:shareInterpolator="true"动画集合中的动画是否公用一个差值器
  • android:startOffset="float"动画延迟时间
透明度动画

透明度动画,通过改变view的透明度展示动画。对应AlphaAnimation和<alpha>xml标签

  • android:fromAlpha="float" 起始透明度,取值范围(-1.0~1.0)
  • android:toAlpha="float"结束时透明度,取值范围(-1.0~1.0)
缩放动画

缩放动画,通过修改view的大小展示动画。对应ScaleAnimation类和<scale>xml表情

  • android:fromXScale="float"动画在水平方向X的起始缩放倍数
  • android:fromYScale="float"动画在水平方向Y的结束缩放倍数
  • android:toXScale="float"动画在竖直方向X的结束缩放倍数
  • android:toYScale="float"动画在竖直方向Y的结束缩放倍数

    // 0.0表示收缩到没有;1.0表示正常无伸缩
    // 值小于1.0表示收缩;值大于1.0表示放大

  • android:pivotX="float"缩放中心点的x坐标
  • android:pivotY="float"缩放中心点的y坐标

// pivotX pivotY,可取值为数字,百分比,或者百分比p
// 设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
// 设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
// 设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT

旋转动画

通过旋转view展示动画。对应RotateAnimation类和<rotate>xml标签

  • android:fromDegrees="float"动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
  • android:toDegrees="float"动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
  • android:pivotX="float"旋转中心点的x坐标 具体如上缩放中心点参数解释
  • android:pivotY="float"旋转中心点的y坐标 具体如上缩放中心点参数解释
平移动画

平移动画,更改view的展示位置展示动画。对应TranslateAnimation类和<translate>xml表情

  • android:fromXDelta="float"view在水平x方向的起始值
  • android:fromYDelta="float"view在水平y方向的起始值
  • android:toXDelta="float"view在水平x方向的结束值
  • android:toYDelta="float" view在水平y方向的结束值
具体动画的使用

应用动画xml配置

TextView textDemo = findViewById(R.id.text_demo);
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.rotate_animation_test);
textDemo.startAnimation(animation);

使用java类配置动画,具体参数类同xml参数,建议使用xml配置动画

AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 2.0f);
textDemo.startAnimation(alphaAnimation);
监听动画
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        //动画开始回调
    }
    @Override
    public void onAnimationEnd(Animation animation) {
        //动画结束回调
    }
    @Override
    public void onAnimationRepeat(Animation animation) {
        //动画重复时回调
    }
});
View动画特殊使用场景
  • Activity 的切换效果
    1. 使用public void overridePendingTransition(int enterAnim, int exitAnim)给activity切换添加动画效果。调用时机在startActivity()或者finish()方法之后调用,否则不起作用。
    2. 配置theme的style
    <style name="AnimationActivity" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/push_left_in</item>
        <item name="android:activityCloseExitAnimation">@anim/push_left_in</item>
        <item name="android:activityOpenExitAnimation">@anim/push_left_out</item>
        <item name="android:activityCloseEnterAnimation">@anim/push_left_out</item>
    </style>
    
  • Fragement 的切换效果
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.setCustomAnimations()
    
  • 视图组(ViewGroup)中子元素的出场效果
    简单来说就是可以在 ViewGroup 的添加一个入场动画,这个 ViewGroup 的所有子元素都会按照你设计的顺序执行一遍动画,至于子元素的范围目测是直接子元素才行。常见的有
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/rotate_animation_test" 
    android:delay="20"
    android:interpolator=""
    android:animationOrder="random"/>
  • android:animation="@anim/rotate_animation_test"
  • android:delay="20"是子元素开始动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5就代表每个子元素都需要延迟150ms才能播放入场动画。总体来说,第一个子元素延迟150ms开始播放入场动画,第二个子元素延迟300ms开始播放入场动画,依次类推。
  • android:animationOrder="random" 子元素入场顺序reverse倒序 normal正常 random随机
    应用:
<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="3dp"
    android:layoutAnimation="@anim/rotate_animation_test"
    android:layout_centerInParent="true">
   ......子view
</RelativeLayout>

属性动画

  属性动画本质是通过改变对象的属性(例如:x,y等属性),来实现动画的,所以基本上是无所不能的,只要对象有这个属性,就能实现动画效果。属性动画是在api11的新特性,通过动态的改变view的属性从而达到动画效果。虽然可以使用nineoldandroid库向下兼容,但是兼容本质是使用补间动画完成,也就是说不会更改view的属性,也不会更改view的位置。属性动画比较常用的类: ValueAnimator、ObjectAnimator、AnimationSet,其中ObjectAnimator是ValueAnimator的子类,而AnminationSet是动画集合

单个动画
ObjectAnimator animator = ObjectAnimator
        .ofInt(textDemo, "backgroundColor", 0XffFF0000, 0Xff0000FF)
        .setDuration(2000);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(10);
animator.start();
动画集合
AnimatorSet animatorSet = new AnimatorSet();
ValueAnimator translationX = ObjectAnimator.ofFloat(textDemo, "translationX", 200f);
ValueAnimator animator = ObjectAnimator
        .ofInt(textDemo, "backgroundColor", 0XffFF0000, 0Xff0000FF);
animatorSet.playTogether(translationX,animator);
animatorSet.setDuration(1000).start();

动画配置同样可以使用xml配置,参数类似,这里不做详细说明。

差值器和估值器

差值器(Interpolator)

根据时间流逝百分比计算当前属性改变百分比。同xml配置动画中的 android:interpolator属性配置,常见有LinearInterpolator(线性差值器)、AccelerateDecelerateInterpolator(加速减速差值器)
等。自定义需要实现Interpolator或者TimeInterpolator。Interpolator接口继承TimeInterpolator。

// Interpolator接口
public interface Interpolator extends TimeInterpolator{ 
    // 内部只有一个方法
     float getInterpolation(float input) {  
         // 参数说明
         // input值值变化范围是0-1,且随着动画进度(0% - 100% )均匀变化
        // 即动画开始时,input值 = 0;动画结束时input = 1
        // 而中间的值则是随着动画的进度(0% - 100%)在0到1之间均匀增加
      ...// 插值器的计算逻辑
      return xxx;
      // 返回的值就是用于估值器继续计算的fraction值,下面会详细说明
    }  
// TimeInterpolator接口
// 同上
public interface TimeInterpolator {  
    float getInterpolation(float input);  
}
估值器(TypeEvaluator)

根据当前属性改变百分比计算改变后的属性值。属性动画特有的属性。自定义估值器需要实现TypeEvaluator接口。

public interface TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
// 参数说明
// fraction:插值器getInterpolation()的返回值
// startValue:动画的初始值
// endValue:动画的结束值
        ....// 估值器的计算逻辑
        return xxx;
        // 赋给动画属性的具体数值
        // 使用反射机制改变属性变化
// 特别注意
// 那么插值器的input值 和 估值器fraction有什么关系呢?
// 答:input的值决定了fraction的值:input值经过计算后传入到插值器的getInterpolation(),然后通过实现getInterpolation()中的逻辑算法,根据input值来计算出一个返回值,而这个返回值就是fraction了
    }  
}

可以对任意属性做属性动画,属性动画要求动画作用的对象提供该属性的get()和set()方法。因为属性动画本质就是根据外界传递的对象属性的初始值和终点值,然后根据估值器和差值器计算属性值,不断调用属性的set方法,通过时间的推移所传递的值,越来越近终点值。
注意:

  • 对象属性必须提供对应的set方法,而且如果没有初始值传入的情况下必须要设置get方法,因为 系统要获取初始值,如果没有满足条件则程序cash
  • 对象属性的set方法对属性做出改变,需要能够通过某种方法表示出来。带来ui展示效果的改变。否则动画不会生效。

ValueAnimator

使用ValueAnimator通过监听动画过程,自己改变对象属性完成动画

        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.setDuration(2000);//动画持续时间
        valueAnimator.setRepeatCount(0);//重复次数
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);//重复方式,
        valueAnimator.setStartDelay(20);//开始前延迟时间
        valueAnimator.setEvaluator(new IntEvaluator());//估值器
        valueAnimator.setInterpolator(new LinearInterpolator());//差值器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取当前动画属性值,即1~100
                Integer animatedValue = (Integer) animation.getAnimatedValue();
                //获取动画的百分比
                float animatedFraction = animation.getAnimatedFraction();
                ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
                int width = layoutParams.width;
                int height = layoutParams.height;
                layoutParams.height = height + 1;
                layoutParams.width=width+1;
                Log.e(TAG,"animatedValue: "+animatedValue+" animatedFraction : "+animatedFraction
                +" width : "+layoutParams.width+" height : "+layoutParams.height);
                textView.requestLayout();
            }
        });
        valueAnimator.start();
    }

注意事项

  • OOM注意,在帧动画中如果图片过大、数量过多容易出现
  • 内存泄漏, 切记在activity销毁时,停止动画。否则一些无限循环动画将导致activity不能释放而内存泄漏。出现在属性动画中,view动画不存在此类问题
  • 兼容性问题,属性动画出现在android3.0以后,虽然有兼容包,但是内部实行是view动画,注意视觉位置和真实位置差异
  • View动画即补间动画,是改变view的视觉位置,改变view的影像展示位置,而不改变真实位置。注意交互体验。可能会出现view动画结束后,view无法隐藏的问题及setVisibility(View.GONE)失效。此时调用view.clearAnimation()清除动画。可修复此类问题
  • 注意适配,动画中的属性都是px的但是切换展示过程中使用dp,
  • 交互问题,在android3.0以前属性动画和view动画都是改变影像位置,不改变真实位置,例如点击依旧在原位置点击响应,而不是新位置,在3.0以后属性动画view真实位置随着影像位置而变交互即在移动后的位置,而view动画仍然在原始位置。
  • 使用动画的过程中,建议使用硬件加速,提高动画的流畅性。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354