Android宝典|动画必考知识点总结

目录

  1. 思维导图
  2. 帧动画
    • 使用方式
    • 优缺点
    • 应用场景
  3. 补间动画
    • 位移、旋转、缩放、透明度动画
    • 优缺点
    • 应用场景
  4. 属性动画
    • 层次关系
    • ValueAnimator
      • ObjectAnimator
      • TimeAnimator
    • AnimatorSet
  5. 插值器、估值器
    • TypeEvaluator
      • IntEvaluator
      • FloutEvaluator
      • ArgbEvaluator
    • TimeInterpolator / Interpolator / BaseInterpolator
      • LinearInterpolator
      • AccelerateDecelerateInterpolator
  6. 参考

思维导图

image

帧动画

使用方式
  1. xml 定义方式

    在 drawable 目录下定义一个 drawable-list,然后给图片设置 res 就好了。

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/ic_vip" android:duration="100"/>
        <item android:drawable="@drawable/ic_account" android:duration="100"/>
        <item android:drawable="@drawable/ic_clouse" android:duration="100"/>
     //...
    </animation-list>
    
    mIvFrame.setImageResource(R.drawable.anim_frame);
    AnimationDrawable drawable = (AnimationDrawable) mIvFrame.getDrawable();
    drawable.start();
    drawable.stop();
    
  2. Java 代码实现

    其实就是用代码构建 AnimationDrawable。

    mAnimationDrawable=new AnimationDrawable();
    for (int i = 0; i < 10; i++) {
        if (i<5){
        mAnimationDrawable.addFrame(getDrawable(R.drawable.ic_vip),100);
        }else {
           mAnimationDrawable.addFrame(getDrawable(R.drawable.ic_clouse),100);
        }
    }
    mIvFrame.setImageDrawable(mAnimationDrawable);
    mAnimationDrawable.start();
    mAnimationDrawable.stop();
    
优缺点

优点:使用简单

缺点:图片是全部加载到内存中,可能导致 OOM。

应用场景

基本上很少使用,可以看成 GIF 图。

补间动画

位移动画
  1. xml 定义方式

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="1000"
            android:toXDelta="100"
            android:toYDelta="100"
            android:fromYDelta="0"
            android:fromXDelta="0"/>
    </set>
    
    mAnimation = AnimationUtils.loadAnimation(mContext, R.anim.anim_trans);
    mIvFrame.startAnimation(mAnimation);
    
  2. Java 代码实现方式

    TranslateAnimation animation = new TranslateAnimation(0, 100, 0, 100);
    animation.setDuration(1000);
    animation.setFillAfter(true);
    mIvFrame.startAnimation(animation);
    
其他动画

类似,不举例了。

优缺点

优点:使用简单

缺点:只改变显示,不改变实际属性

应用场景

基本上大部分动画都能实现,常见于 Activity 转场动画等等

属性动画

层次关系

Animator

  • AnimatorSet
  • ValueAnimator
    • ObjectAnimator
    • TimeAnimator
ValueAnimator

常用使用方式:

    private void setAnimator() {
        mValueAnimator = new ValueAnimator();
        mValueAnimator.setIntValues(0, 500);
        mValueAnimator.setDuration(2000);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.i(TAG, "onAnimationUpdate: " + animation.getAnimatedValue());
                float y = ((int) animation.getAnimatedValue()) * 1.0f;
                mIvFrame.setTranslationY(y);
            }
        });
        mValueAnimator.start();
    }
ObjectAnimator
        ObjectAnimator animator = ObjectAnimator
                .ofFloat(mBtnStart, "translationY", 0, 200)
                .setDuration(2000);
        animator.start();

ObjectAnimator 在每次更新的时候会自动走 setXxx 方法,所以就不需要像 ValueAnimator 一样手动添加监听器,但是 ValueAnimator 的灵活性更好。

TimeAnimator

同样是继承至 ValueAnimator,但是它只做一件事:提供一个时间流,每 18ms 回调一次。

        mTimeAnimator = new TimeAnimator();
        mTimeAnimator.setTimeListener(new TimeAnimator.TimeListener() {
            @Override
            public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
                //动画执行的总时间_动画从上一桢到当前桢的间隔时间,单位都是毫秒
                Log.i(TAG, "onTimeUpdate: " + totalTime + "   " + deltaTime);
            }
        });

运行结果:

2018-12-30 09:01:54.344 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 0   0
2018-12-30 09:01:54.346 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 0   0
2018-12-30 09:01:54.356 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 7   7
2018-12-30 09:01:54.375 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 24   17
2018-12-30 09:01:54.388 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 42   18
2018-12-30 09:01:54.407 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 60   18
2018-12-30 09:01:54.424 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 78   18
2018-12-30 09:01:54.444 6656-6656/com.example.omooo.demoproject I/AnimatorActivity: onTimeUpdate: 96   18

估值器、插值器

估值器表示属性的从初始值过渡到结束值变化的具体数值,而插值器则表示变化率,比如先加速后减速(默认)、匀速等等。

估值器

估值器都需要实现 TypeEvaluator 接口:

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);
}

其实就是根据初始值和结束值算出一个值。

系统已经有几个默认实现,比如 ArgbEvaluator、IntEvaluator、FloatEvaluator 等等。其实我们在用 ValueAnimator.ofArgb() 的时候,内部就是用 ArgbEvaluator 实现的,那对于 ValueAnimator.ofInt()、ValueAnimator.ofFloat() 方法是不是也是一样的道理呢?

下面将介绍如何自定义估值器,所实现的功能:

image

首先定义按钮所需要的属性:

public class ButtonInfo {
    public int color;
    public int x;
    public int y;

    public ButtonInfo(int color, int x, int y) {
        this.color = color;
        this.x = x;
        this.y = y;
    }

    public ButtonInfo() {
    }
}

自定义估值器:

public class ButtonEvaluator implements TypeEvaluator {

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        ButtonInfo start = (ButtonInfo) startValue;
        ButtonInfo end = (ButtonInfo) endValue;
        ButtonInfo buttonInfo = new ButtonInfo();
        ArgbEvaluator argbEvaluator = new ArgbEvaluator();
        buttonInfo.color = (int) argbEvaluator.evaluate(fraction, ((ButtonInfo) startValue).color, ((ButtonInfo) endValue).color);
        buttonInfo.x = (int) (fraction * (end.x - start.x) + start.x);
        buttonInfo.y = (int) (fraction * (end.y - start.y) + start.y);
        return buttonInfo;
    }
}

运用:

    private void setTransAnimator() {
        mValueAnimator = ValueAnimator.ofObject(new ButtonEvaluator(), new ButtonInfo(0xff94E1F7, 0, 0)
                , new ButtonInfo(0xffF35519, 500, 500));
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ButtonInfo buttonInfo = (ButtonInfo) animation.getAnimatedValue();
                mBtnStart.setBackgroundColor(buttonInfo.color);
                mBtnStart.setTranslationX(buttonInfo.x);
                mBtnStart.setTranslationY(buttonInfo.y);
            }
        });
        mValueAnimator.setDuration(5000);
        mValueAnimator.start();
    }

可以,看出,实际上自定义估值器还是很简单。

插值器

插值器需要实现 TimeInterpolator 或 Interpolator:

public interface TimeInterpolator {
    float getInterpolation(float input);
}

public interface Interpolator extends TimeInterpolator {
    
}

Android 系统内置了几种实现,默认是先加速后减速,即 AccelerateDecelerateInterpolator ,看一下源码实现:

public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    //...
}

四五十行代码,首先明确的就是 value 值是 0 ~ 1,所以以上就是表示余旋函数在 pi/2 和 pi 之间,就是先加速后减速。

那我们在看一下 LinearInterpolator 的源码:

/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    public float getInterpolation(float input) {
        return input;
    }
    //...
}

那在自定义插值器就易如反掌了呀,定义一个先减速后加速的插值器,如下:

public class DeceAcceInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        //余旋函数 0 ~ PI/2
        return (float) Math.cos(input * Math.PI / 2);
    }
}

然后给 ValueAnimator 设置自定义的插值器:

mValueAnimator.setInterpolator(new DeceAcceInterpolator());
image

啊?怎么反向了?看来设置变化率需要在 x 轴的下方呀。至于为什么?留个坑。

参考

Android 动画 Animator 家族使用指南

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

推荐阅读更多精彩内容