Android 动画

视图动画:

AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation 和 动画集:AnimationSet

  • AlphaAnimation(透明度动画):
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
view.startAnimation(alphaAnimation);
  • RotateAnimation(旋转动画):
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, 
RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F);
rotateAnimation.setDuration(1000);
view.startAnimation(rotateAnimation);
  • TranslateAnimation(位移动画):
TranslateAnimation  translateAnimation = new TranslateAnimation(0, 200, 0, 0);
translateAnimation.setDuration(1000);
view.startAnimation(translateAnimation);
  • ScaleAnimation(缩放动画):
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, 
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
view.startAnimation(scaleAnimation);
  • AnimationSet(动画集合):
AnimationSet animationSet = new AnimationSet(true);
        animationSet.setDuration(4000);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(rotateAnimation);
        animationSet.addAnimation(translateAnimation);
        animationSet.addAnimation(scaleAnimation);
        animationSet.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.e(TAG, "onAnimationStart: 动画开始执行的时候调用");
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.e(TAG, "onAnimationEnd: 动画结束执行的时候调用");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.e(TAG, "onAnimationRepeat: 动画重复执行的时候调用");
            }
        });
//启动动画
view.startAnimation(animationSet);

属性动画

PropertyValuesHolder、Animator、ObjectAnimator 、ValueAnimator

  • ObjectAnimator :

ObjectAnimator 是属性动画框架中最重要的实行类,创建一个ObjectAnimator只需要通过它的静态工厂类直接返回一个ObjectAnimator对象.(通过ofxxx方法);
必须具备get 、set方法,不然ObjectAnimator就无法起效;

  • 1.translationX 和 translationY:控制view对象从布局容器的左下方坐标偏移的位置;
  • 2.rotation 、rotationX 和 rotationY:控制view对象围绕它的支点进行2D和3D旋转;
  • 3.scaleX 和 scaleY: 控制view对象围绕它的支点进行2D缩放;
  • 4.pivotX 和 pivotY:这两个属性控制着View对象的支点位置, 围绕这个支点进行旋转和缩放变换处理;
    默认情况下,该支点的位置就是view的中心点;
  • 5.alpha:它表示view对象的alpha透明度,默认值是1(不透明) ,0代表完全透明(不可见);
    如果没有get set方法,那么可以自定义一个属性或者包装类,来间接地给这个属性增加get set方法, 或者通过ValueAnimator来实现;
  1. 自带属性:
ObjectAnimator  objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 200);
objectAnimator.setDuration(1000);
objectAnimator.start();

 ObjectAnimator animatorColor = ObjectAnimator.ofInt(view,"BackgroundColor",0xffff0000,0xff00ff00);
animatorColor.setEvaluator(new ArgbEvaluator());
animatorColor.setDuration(1000);
animatorColor.start();
  1. 自定义属性:
public class WrapperView {

    private View view;

    public WrapperView(View view) {
        this.view =view;
    }

    public int getWidth(){
        return view.getLayoutParams().width;
    }

    public void setWidth(int width) {
        view.getLayoutParams().width = width;
        view.requestLayout();
    }
}

WrapperView wrapperView = new WrapperView(tvWrapper);
ObjectAnimator objectAnimatorWrapper = ObjectAnimator.ofInt(wrapperView, "width", 100).setDuration(1000);
        objectAnimatorWrapper.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                Log.e(TAG, "onAnimationStart: 动画开始执行的时候调用");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //这个应该是用得最多的吧
                Log.e(TAG, "onAnimationEnd: 动画结束执行的时候调用");
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                Log.e(TAG, "onAnimationEnd: 动画取消执行的时候调用");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                Log.e(TAG, "onAnimationEnd: 动画重复执行的时候调用");
            }
        });
objectAnimatorWrapper.start();

  • PropertyValuesHolder:

类似AnimationSet

  1. 动画合并:
PropertyValuesHolder valuesHolderTranslastion = PropertyValuesHolder.ofFloat("translationX", 100f);
PropertyValuesHolder valuesHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.3f);
PropertyValuesHolder valuesHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.3f);
PropertyValuesHolder valuesHolderColor = PropertyValuesHolder.ofInt("BackgroundColor", 0xff888888, 0xff00ff00);
ObjectAnimator objectAnimatorProper = ObjectAnimator.ofPropertyValuesHolder(tvObjProperty, valuesHolderTranslastion, valuesHolderScaleX, valuesHolderScaleY, valuesHolderColor);
objectAnimatorProper.setDuration(1000);
objectAnimatorProper.start();
  1. 动画拆分:
 // 在 0% 处开始向X移动
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 时间经过 50% 的时候,动画完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 时间见过 100% 的时候,动画完成度倒退到 0%位置
Keyframe keyframe3 = Keyframe.ofFloat(1, 0);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(tvObjPropertyKey, holder);
animator.start();

  • ValueAnimator:

ValueAnimator 是 ObjectAnimator 的父类,ValueAnimator 就是一个不能指定目标对象版本的 ObjectAnimator

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1000);
        valueAnimator.setTarget(view);
        valueAnimator.setDuration(1000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
              // TODO: 2018/10/24
                float value = (float) animation.getAnimatedValue();
                if (value==500f){
                    ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                    scaleAnimation.setDuration(100);
                    view.startAnimation(scaleAnimation);
                }
            }
        });

  • Animator:

res/animator下创建布局文件,代码加载xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType">
</objectAnimator>

Animator animatorXml = AnimatorInflater.loadAnimator(MainActivity.this,R.animator.animator_xml);
animatorXml.setTarget(view);
animatorXml.start();

AnimationUtils (工具类)

  • Android SDK 提供的工具类:
返回值 公共方法 描述
static long currentAnimationTimeMillis() 以毫秒返回当前动画时间
static Animation loadAnimation(Context context, int id) 从资源加载动画对象
static Interpolator loadInterpolator(Context context, int id) 从资源中加载内插器对象
static LayoutAnimationController loadLayoutAnimation(Context context, int id) 从资源加载动画对象(返回值不同)
static Animation makeInAnimation(Context c, boolean fromLeft) 用布尔参数决定滑入的方向是左侧还是右侧向上
static Animation makeInChildBottomAnimation(Context c) 视图总是从屏幕的底部向上滑入
static Animation makeOutAnimation(Context c, boolean toRight) 用布尔参数决定滑入的方向是左侧还是右侧
animation = AnimationUtils.loadAnimation(this, R.anim.animation_utils);
view.startAnimation(animation);

ViewAnimationUtils (5.X的工具类)

createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius)

  • centerX : 中心点X坐标;
  • centerY : 中心点Y坐标;
  • startRadius: 动画圆的起始半径;
  • endRadius: 动画圆的结束半径.
ViewAnimationUtils.createCircularReveal(ImageView, centerX, centerY, mImageView.getWidth(), 0);

Interpolator(插值器)

Interpolator 其实就是速度设置器。你在参数里填入不同的 Interpolator ,动画就会以不同的速度模型来执行;Google TimeInterpolator

  • AccelerateDecelerateInterpolator:

先加速再减速。这是默认的 Interpolator;

  • LinearInterpolator:

匀速;

  • AccelerateInterpolator:

持续加速;

  • DecelerateInterpolator:

以最高速开始,持续减速直到停止;

  • AnticipateInterpolator:

先回退一下段,然后再正常运动;

  • OvershootInterpolator:

到终点的时候超出一下段,然后弹回来;

  • AnticipateOvershootInterpolator:

开始前回拉,最后超过一些然后回弹;

  • BounceInterpolator:

到达终点的时候弹回来两下,然后回到终点;

  • CycleInterpolator:

这个也是一个正弦 / 余弦曲线,不过它和 AccelerateDecelerateInterpolator 的区别是,它可以自定义曲线的周期,所以动画可以不到终点就结束,也可以到达终点后回弹,回弹的次数由曲线的周期决定,曲线的周期由 CycleInterpolator() 构造方法的参数决定。

  • PathInterpolator:

自定义动画完成度 / 时间完成度曲线。
用这个 Interpolator 你可以定制出任何你想要的速度模型。定制的方式是使用一个 Path 对象来绘制出你要的动画完成度 / 时间完成度曲线

  • FastOutLinearInInterpolator(5.0以上):

贝塞尔曲线的持续加速的运动路线,AccelerateInterpolator比FastOutLinearInInterpolator斜率要低一点;

  • FastOutSlowInInterpolator(5.0以上):

贝塞尔曲线,前期加速度要快得多;

  • LinearOutSlowInInterpolator(5.0以上):

减速曲线,初始速度更高;


SVG(矢量动画)

  • Android 5.X增加了对SVG矢量图的支持(VectorDrawable,AnimatedVectorDrawable):
    <path>标签支持的指令:
  • M: 移动 moveTo;
  • L: 直线;
  • H: 水平线;
  • V: 垂直线;
  • C: 三次贝塞尔曲线;
  • S: 三次贝塞尔曲线;
  • Q: 二次贝塞尔曲线;
  • T: 映射前面路径后的终点;
  • Z: 关闭路径;
  • A: 弧线;
  • RX,RY表示椭圆半圆的半轴大小;
  • XROTATION表示X轴与水平方向的顺时针方向的夹角;
  • FLAG1有两个值:1.表示大角度的弧线,0.表示小角度弧线;
  • FLAG2有两个值,确定从起点至终点的方向:1.表示顺时针,0.表示逆时针;
  • X,Y轴为终点坐标;

1.大小写效果一样,2.坐标轴和canvas一样左上角(0,0),3.指令和数据间的空格可以省略,4.同个指令出现多个时候可以只用一个。

   defaultConfig {
        //配置信息
        vectorDrawables.useSupportLibrary = true
    }
<!--res/drawable下新建-->
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="100dp"
    android:width="100dp"
    android:viewportWidth="100"
    android:viewportHeight="100">
    <group>
        <path
            android:name="path1"
            android:strokeColor="@color/colorPrimaryDark"
            android:strokeWidth="5"
            android:strokeLineCap="round"
            android:pathData="M 20,80 L 50,80 80,80"/>
    </group>

    <group>
        <path
            android:name="path2"
            android:strokeColor="@color/colorPrimaryDark"
            android:strokeWidth="5"
            android:strokeLineCap="round"
            android:pathData="M 20,20 L 50,20 80,20"/>
    </group>
</vector>


<!--res/animator下新建-->
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="pathData"
    android:valueFrom="M 20,80 L 50,80 80,80"
    android:valueTo="M 20,80 L 50,50 80,80"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">
</objectAnimator>

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:propertyName="pathData"
    android:valueFrom="M 20,20 L 50,20 80,20"
    android:valueTo="M 20,20 L 50,50 80,20"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">

</objectAnimator>

<!--res/drawble-v21下新建-->
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/svg_line">

    <target
        android:name="path1"
        android:animation="@animator/animator_svg_path1"/>

    <target
        android:name="path2"
        android:animation="@animator/animator_svg_path2"/>
</animated-vector>

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    Drawable drawable = imageViewSVG.getDrawable();
                    if (drawable instanceof Animatable){
                        ((Animatable) drawable).start();
                    }
                }

SVG编辑器链接
本项目的简单Demo地址


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

推荐阅读更多精彩内容

  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 6,117评论 1 38
  • 动画基础概念 动画分类 Android 中动画分为两种,一种是 Tween 动画、还有一种是 Frame 动画。 ...
    Rtia阅读 1,223评论 0 6
  • Animation Animation类是所有动画(scale、alpha、translate、rotate)的基...
    四月一号阅读 1,900评论 0 10
  • 目前我的工作是法语导游,接待法语国家的游客来我国游玩。我的法语是自学的,所以想和对法语有兴趣的同学分享一下。 1....
    心的新旅行阅读 417评论 7 1
  • 独立思考的能力,我想这是我目前最欠缺的吧。人的惰性作祟,很多时候都奉行拿来主义。遇到问题不会,没有通过自己的思考,...
    黑赛矩阵阅读 169评论 2 1