Android 动画的一些理解

·  阅读 683
Android 动画的一些理解

在Android中,动画一直是交互的一个很好手段,在平时的项目开发中,经常要用到一些动画的交互,每次拿着一个gif跑过来说,这个动画可以实现吗?每次都硬着头皮说,可以。然而对于我这种Android小白来说,确实是有一点难度,所以就有了今天这篇关于Android动画的一些理解,希望对大家有帮助!!!

本文知识点:

  • Android动画的分类:
  • 视图动画的使用:
  • 帧动画的使用:
  • 属性动画的使用:

1. Android动画的分类:

Android 中动画可以分为:

  • 位移动画
    • 平移 TranslateAnimation
    • 旋转 RotateAnimation
    • 缩放 ScaleAnimation
    • 透明度 AlphaAnimation
  • 帧动画
  • 属性动画

2.视图动画的使用

首先,我真的不知道是不是叫这个名字,网上叫什么名字的都有,就先这么叫吧!管他呢?反正你知道是什么东西就好了!这里先说一下缺点,所有视图动画改变View的操作都是改变的显示位置,而并非改变的实际位置,下面是视图动画里面用到的一些公共属性!

  • android:duration 动画执行时间
  • android:fillAfter 动画结束后View是否停留在结束位置
  • android:interpolator 插值器默认为(加速减速插值器)
  • android:shareInterpolator 是否共享插值器

一张图让你理解视图动画的位置实际并没有改变!

这里强烈说明一点,就是动画存放的位置,一开始我总是分不清具体的存放位置,其实现在也分不清!!!一定是在res下面创建anim文件夹 : res/anim/XXX.xml,并且内部的标签一定是set标签!!!这里唠叨一句,当你新创建的项目是没有anim文件夹的,这个时候是需要你自己创建的!

###2.1 平移动画 (TranslateAnimation)

平移动画的效果就不去结束了。这里简单介绍一下里面用到的属性!

  • fromXDelta 表示x的起始值,比如0,0%p
  • fromYDelta 表示y的起始值,比如100,100%p
  • toXDelta 表示x的结束值
  • toYDelta 表示y的结束值

这里如果直接设置距离的话,是从控件的原始位置开始计算的距离,如果设置百分比0%和100%都是相当于父控件而言的,其实位置设置的是控件开始的位置开始计算!这两点记住就可以了,剩下的看一下效果就可以了!

主要看底部的Toast

上面用到的XML设置为:

<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fillAfter="true">

    <translate
        android:fromXDelta="0"
        android:toXDelta="100%" />
</set>
复制代码

其实这里我只设置了X轴的位移,感兴趣的童鞋可以设置一下Y轴的距离看下效果!当然上面的代码也是可以通过代码进行设置的!像这个样子。。。

    //代码设置
    TranslateAnimation translateAnimation = new TranslateAnimation(0,1000,0,0);
    translateAnimation.setDuration(500);
    translateAnimation.setFillAfter(true);
    mIvIcon.startAnimation(translateAnimation);
复制代码

2.2 旋转动画(RotateAnimation)

“旋转跳跃,我闭上眼”就是这种效果了,旋转动画只要你注意好中心点位置的确定就可以了。先看一下常用的属性!!!

  • android:fromDegrees 旋转的开始角度
  • android:toDegrees 旋转的结束角度
  • android:pivotX 旋转的x轴点
  • android:pivotY 旋转的y轴点

上面用到的XML设置为:

<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fillAfter="true">

    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" />
</set>
复制代码

上面效果代码设置为:

    RotateAnimation rotateAnimation = new RotateAnimation(0, 360, mIvIcon.getWidth() / 2, mIvIcon.getHeight() / 2);
    rotateAnimation.setDuration(1000);
    mIvIcon.startAnimation(rotateAnimation);
复制代码

2.3 缩放动画(ScaleAnimation)

缩放动画的缩放位置的确定对于整个动画是至关重要的一个点,如果你位置选择的不对,那么效果会差很远,所以选择位置是最为重要的!!!先介绍一下相应的属性

  • android:fromXScale x水平方向缩放起始值,比如:0
  • android:fromYScale y水平方向缩放起始值,比如:0
  • android:toXScale x竖直方向缩放起始值
  • android:toYScale y竖直方向缩放起始值
  • android:toXScale 缩放轴点的X坐标
  • android:toYScale 缩放轴点的Y坐标

上面用到的XML设置为:

<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fillAfter="true">

    <scale
        android:fromXScale="100%"
        android:fromYScale="100%"
        android:pivotX="0"
        android:pivotY="0"
        android:toXScale="50%"
        android:toYScale="50%" />
</set>
复制代码

上面效果代码设置为:

    ScaleAnimation scaleAnimation = new ScaleAnimation(mIvIcon.getWidth(), mIvIcon.getWidth() / 2, mIvIcon.getHeight(), mIvIcon.getHeight() / 2, 0, 0);
    scaleAnimation.setDuration(1000);
    mIvIcon.startAnimation(scaleAnimation);
复制代码

这里其实你知道只要一个东西,缩放点和缩放的距离,只要计算好这个就可以了!

2.4 渐变动画 (AlphaAnimation)

这个动画就比较好理解了!就是透明度的变化而已!!!属性如下:

  • android:fromAlpha 透明度的起始值
  • android:toAlpha 透明度的结束值

上面用到的XML设置为:

<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fillAfter="true">

    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.5" />
</set>
复制代码

上面效果代码设置为:

    AlphaAnimation scaleAnimation = new AlphaAnimation(1, 0);
    scaleAnimation.setDuration(1000);
    mIvIcon.startAnimation(scaleAnimation);
复制代码

上面所有XML的加载的代码如下:

    Animation translateAnimation = AnimationUtils.loadAnimation(this,R.anim.XXX);
    mIvAnimation.startAnimation(translateAnimation);
复制代码

当然你也可以直接把上面所有的动画加以组合,写在一个XML中,像这样

<?xml version="1.0" encoding="utf-8"?><!--平移动画的显示-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:fillAfter="true">

    <translate
        android:fromXDelta="0"
        android:toXDelta="100%" />

    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" />

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

    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.5" />
</set>
复制代码

其实有的人很纠结,视图动画是用代码写还是用XML去写,其实我个人觉得,动画还是写在xml中,因为这样,复用的可能性很大,如果你用代码写,除非写个工具类。这个就看你们的需求了,不要去纠结这个东西,喜欢就好!

2.5 设置相应的监听

有些特殊需要,在动画执行完成的时候做一些相应的操做,所有就要监听动画的执行的一些状态,如:开始、结束、再次执行!相应的监听方法如下:

animaton.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //动画开始时回调
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //动画结束时回调
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                //对话重复执行的时候回调
            }
        });
复制代码

基本上平时的项目中关于视图动画就能用到这么多,有什么总结不到位的还请个位大神指教!!!

2.6 一些项目中的使用案例

2.6.1 ViewGroup上面使用视图动画

关于这个内容来说的话,可就厉害了。怎么厉害呢?其实这种动画效果时很好的!先看一张实现的效果图!

上面的图片时视图动画配合layoutAnimation实现的,还是比较好看的吧!这里就有一个相应的layoutAnimation的概念了!它是操作整个ViewGroup的动画(可以是任何的ViewGroup的控件),可以实现延时的效果!先介绍一下相应的属性吧!

  • android:delay 表示动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5表示每个子元素都需要延迟150ms才能播放入场动画
  • android:animationOrder 表示动画元素的顺序,有三种顺序选项:normal,reverse,random在其中normal表示顺序显示;reverse表示逆向显示;random则表示随机显示
  • android:animation 为元素指定具体的入场的动画

上面就是一些相应的属性标签了。下面我们来看看怎么使用!其实也很简单, 当你创建这个动画的使用像这样创建

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
                 android:animation="@anim/translate_animation"//这里设置的是内部子View的动画样式!!!
                 android:animationOrder="normal"
                 android:delay="0.5"/>
复制代码

你可以将这个xml使用在需要的控件中 ,像这样android:layoutAnimation="@anim/item_layoutanimation"

也可以使用代码设置像这样

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXX);
    LayoutAnimationController controller = new LayoutAnimationController(animation);
    controller.setDelay(0.5f);
    controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
    View.setLayoutAnimation(controller);
    View.startAnimation(animation);//这句是开始动画用的
复制代码

这里注意一点就是XXX代表的是普通的动画,而不是layoutAnimation为根节点的动画哦!!!动画的XML别弄错了!这个让我想起了当时写MD的时候用到的相应的动画,感觉和这个一样!嘻嘻...

  • Activity切换的动画

关于这个问题我之前在MD的文章中说到过,所以这里就不说了!感兴趣的童鞋可以看看MaterialDesign系列文章(三)过渡动画的实现这里就不说明了!哈哈,其实我发现我真的很懒,不是吗?

3.帧动画的使用:

关于帧动画的使用方案,基本上都大同小异,美工丢过来一套图,然后你设置一下。最后展示就可以了,基本上流程都是一样的!但是对于帧动画的缺点就是,当你使用的图片多了的时候,很容易OOM。所以动画不多的情况下建议使用帧动画,否则不建议使用!!!使用帧动画的大体流程是这样的!

共有属性介绍:

  • android:oneshot="false" false 无限循环

使用步骤介绍:

  • 创建相应的帧动画文件:(注意啊!这个文件的位置是drawable,而不是anim了)
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">

    <item
        android:drawable="@mipmap/icon1"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/icon2"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/icon3"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/icon4"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/icon5"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/icon6"
        android:duration="500"/>
</animation-list>
复制代码
  • 加载相应的动画
imageView.setBackgroundResource(R.drawable.animation_list);
AnimationDrawable drawable = (AnimationDrawable)view.getBackground();
drawable.start();
复制代码

4.属性动画的使用

属性动画时在Android3.0中引用的,相对有视图动画来说。可以改变控件的位置!内部实现时是通过改变控件的属性值进行作用的!因为这个原因,所以可以改变View相应的具体大小和位置等一系列相应的属性!其实关于属性动画包含的内容包含:

  • ValueAnimator
  • ObjectAnimator 继承ValueAnimator
  • TimeAnimator 继承ValueAnimator
  • AnimatorSet 动画集合
  • 属性动画的XML设置
  • 遇到的问题

我们就一个一个来说吧!ValueAnimator这个是3.0属性动画的父类,提供了一些常用的方法,供子类实现!所以这里就直接跳过这段,直接讲解相应的子类,所谓的子承父业,子类明白了!父类就明白了!

4.1 ValueAnimator的使用

你说这个是显现动画的吧!其实还不算,他只是改变相应的属性而已!因为是父类,没有什么好说明的,但是它有一个常用的场景,就是动态改变对象的某些属性!像下面这样!!!

ValueAnimator animator = ValueAnimator.ofInt(0,400);  
animator.setDuration(1000);  
  
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        //这里你可以动态的改变一些属性
    }  
});  
animator.start();  
复制代码

4.2 ObjectAnimator的使用

这个类可就厉害了,是通过改变相应的属性,来实现动画的,那么问题来了,所谓的属性都有哪些呢?最开始的时候我接触这个动画,说是属性动画,但是具体都包含哪些属性我怎么知道呢?后来我知道了,但凡有get/set方法的属性都可以设置,先给你们来到开胃菜!!!先看看下面这个效果!

    ValueAnimator colorAnim = ObjectAnimator.ofInt(mRvBg, "backgroundColor", 0xffff8080, 0xff8080ff);
    colorAnim.setDuration(3000);
    colorAnim.setEvaluator(new ArgbEvaluator());/*设置估值器*/
    colorAnim.setInterpolator(new AccelerateDecelerateInterpolator());/*设置插值器*/
    colorAnim.setRepeatCount(ValueAnimator.INFINITE);/*设置循环次数,这里是无限循环的*/
    colorAnim.setRepeatMode(ValueAnimator.REVERSE);/*设置循环模式-这里设置的是逆向模式*/
    colorAnim.start();
复制代码

这个是通过改变背景,实现的效果。那么问题来了,我怎么知道有什么属性可以设置!你只要明白属性这个概念就行,你平时用json接受数据的时候,里面的参数就是属性!怕你不懂,这里还是来张图大概看看就可以了!

就像这样的,这个只是一部分,就是一些可以设置的属性!他还是不懂,还是不懂!就去View页面直接找就好了!!!

常用的API:

  • setDuration 设置时间
  • setEvaluator 设置估值器
    • IntEvaluator (针对帧数属性)
    • FloatEvaluator (针对浮点数属性)
    • ArgbEvaluator (针对Color属性)
  • setInterpolator 设置插值器
    • TimeInterpolator 时间插值器
    • LinearInterpolator 线性插值器(匀速动画)
    • AccelerateDecelerateInterpolator 加速减速插值器(动画两头慢中间快)
    • DecelerateInterpolator 减速插值器(动画越来越慢)
  • setRepeatCount 设置循环次数
  • setRepeatMode 设置模式

还有很多的API没有实际用到,也不太好意思和大家说!怕我自己理解错了,误导大家!嘻嘻。。。

其实关于属性动画,只要你记住它改变的属性就好了,变化后就会实实在在的显示在那里了(或者位置实实在在的发生变化)!所以并不会存在视图动画那种只改变显示的问题!一般在项目中用到最多的写法像下面这样!

    ObjectAnimator.ofFloat(mIvAnimation, "rotationX", 0, 360),//X轴旋转
    ObjectAnimator.ofFloat(mIvAnimation, "rotationY", 0, 180),//Y轴旋转
    ObjectAnimator.ofFloat(mIvAnimation, "rotation", 0, -90),//旋转
    ObjectAnimator.ofFloat(mIvAnimation, "translationX", 0, 90),//x轴平移
    ObjectAnimator.ofFloat(mIvAnimation, "translationY", 0, 90),//y轴平移
    ObjectAnimator.ofFloat(mIvAnimation, "scaleX", 1, 1.5f),//X轴缩放
    ObjectAnimator.ofFloat(mIvAnimation, "scaleY", 1, 0.5f),//Y轴缩放
    ObjectAnimator.ofFloat(mIvAnimation, "alpha", 1, 0.25f, 1)//渐变
复制代码

这里面引号里面的都是相应的属性值,直接写属性名称就好了!其实ObjectAnimator还有ofInt()等的一些API这些API和他的区别主要是操作的属性类型有关,因为怕丢失精度吧!!!还有一些ofMultiFloat()等一些API是可以同时操作多个属性值的API,这里面大家自己尝试一下就可以了!和上面的写法都大同小异。对了不知道你们在赋值参数的时候,看不看提示,其实ofFloat最后一个参数传入的是一个可变数组,说明最后可以传入无限个参数(只要你想!!!)。

这里面还差一个监听的问题:关于监听

 public static interface AnimatorListener {
    //动画开始的监听,初始化一些资源
    void onAnimationStart(Animator animation);
    //动画结束的监听,释放一些资源
    void onAnimationEnd(Animator animation);
    //动画取消的监听,释放一些资源
    void onAnimationCancel(Animator animation);
    //动画重复执行的监听,重置一些参数
    void onAnimationRepeat(Animator animation);
}
复制代码

4.3 TimeAnimator使用

这个是根据时间变化来设置一些属性的,提供了一个简单的回调机制,通过 TimeAnimator.TimeListener,在动画的每一帧处通知你。这个动画器没有时间,插值或是对象值设定。回调监听器为每一帧动画接受信息,包括总运行时间和从前一帧到现在的运行时间。里面的方法很少,就一个监听然后返回给你总时间和当前一帧的时间!具体的监听如下:

    public static interface TimeListener {
        void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime);
    }
复制代码

4.4 AnimatorSet 动画集合

把你需要的动画集合整合到一起执行!也可以按照一定的顺序去执行!

    AnimatorSet set = new AnimatorSet();
    set.playTogether(
        ObjectAnimator.ofFloat(mIvAnimation, "rotationX", 0, 360),//X轴旋转
        ObjectAnimator.ofFloat(mIvAnimation, "rotationY", 0, 180),//Y轴旋转
        ObjectAnimator.ofFloat(mIvAnimation, "rotation", 0, -90),//旋转
        ObjectAnimator.ofFloat(mIvAnimation, "translationX", 0, 90),//x轴平移
        ObjectAnimator.ofFloat(mIvAnimation, "translationY", 0, 90),//y轴平移
        ObjectAnimator.ofFloat(mIvAnimation, "scaleX", 1, 1.5f),//X轴缩放
        ObjectAnimator.ofFloat(mIvAnimation, "scaleY", 1, 0.5f),//Y轴缩放
        ObjectAnimator.ofFloat(mIvAnimation, "alpha", 1, 0.25f, 1)//渐变
    );
    set.setDuration(500).start();
复制代码

代码没有什么好说的,只是看一下写法就可以了!playTogether()这一个API!如果你像让动画一个一个的执行,换一个API (playSequentially(Animator... items)) 就可以了!代码在这里就不贴了!!!里面还有一些方法,什么是否开始,是否正在运行的!大家去看一下就可以了!

4.5 属性动画的XML设置

属性动画的各个参数都比较好理解,在XML中可以定义ValueAnimation,ObjectAnimator以及AnimatorSet,其中AnimatorSet对应标签,ValueAnimator对应标签,ObjectAnimator对应标签,惯例先说名一下可以使用的标签

  • <Set>标签的详细属性

    • android:ordering动画的播放顺序,有两个参数可选;
      • 1.together代表所有子动画同时执行;
      • 2.sequentially代表所有子动画按照先后顺序执行.默认是together
  • <objectAnimator> 和 <animator>标签的详细属性

    • android:propertyName 表示属性动画的作用对象的属性名称
    • android:duration 表示动画的时长
    • android:valueFrom 表示属性动画的初始值
    • android:valueTo 表示属性的结束值
    • android:startOffset 表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才能真正播放动画
    • android:repeatCount 表示动画的重复次数
    • android:repeatMode 表示动画的重复模式
    • android:valueType 表示Android:propertyName所制定的属性的类型,有"intType"和"floatType"两个选项,分别代表整型和浮点型,如果android:propertyName所指定的属性表示的是颜色的话,那么就不需要指定android:valueType系统会自动对颜色类型进行属性处理

ps:这做下说明:

  1. android:repeatCount 表示动画循环的次数 默认是0 当为-1的时候表示无线循环
  2. android:repeatMode 表示动画的循环模式 逆向重复的时候是指当第一次播放完成的时候,第二次会倒着播放动画,第三次在从头开始播放动画,第四次在倒着播放,以此循环

XML实例

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="together">

    <objectAnimator
        android:duration="300"
        android:propertyName="x"
        android:valueTo="200"
        android:valueType="intType"/>

    <objectAnimator
        android:duration="300"
        android:propertyName="y"
        android:valueTo="200"
        android:valueType="intType"/>
</set>
复制代码

代码中使用

    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_anim);
    set.setTarget(mIvAnimation);
    set.start();
复制代码

还是强烈建议使用动画的时候最好使用XML去写,因为这样可以更好的复用!相信我,要么你每次写动画的时候都会写一堆代码!

4.5 遇到的问题

任意对象使用属性动画必要条件:

  • 要有相应的get/set方法,否则会报异常
  • 相应的get/set方法要能直观的从UI层面上反应出来,否则看不见效果
  • 还有一点要注意的是这个属性动画是作用在View的对象上,所以应该是View有的属性,而不是继承它的对象重新生成的属性

针对于继承的View要使用属性动画的情况,官方给出了相应的解决方案:

  • 给对象加上相应的get/set方法(如果你有权限的话)
  • 用一个类来包装原始对象,间接的提供get/set方法
   /**
    * author :  贺金龙
    * create time : 2017/10/29 14:21
    * description : 包装类,为了向外面提供相应的get/set方法
    * instructions : 因为没有相应改变宽度和高度的方法,所以这里自己包装一个相应的get/set方法
    * version :
    */
   public class ViewWrapper {
       private View mTargetView;
   
   
       /**
        * author :  贺金龙
        * create time : 2017/10/29 14:28
        * description : 传入相应的View,进行设置一些内容
        * instructions :
        * version :
        */
       public void setTargetView(View targetView) {
           mTargetView = targetView;
       }
   
       /**
        * author :  贺金龙
        * create time : 2017/10/29 14:30
        * description : 获取宽度的方法
        * instructions :
        * version :
        */
       public int getWidth() {
           return mTargetView.getLayoutParams().width;
       }
   
       /**
        * author :  贺金龙
        * create time : 2017/10/29 14:31
        * description : 设置宽度的方法
        * instructions : 设置相应的宽度
        * version :
        *
        * @param width 宽度
        */
       public void setWidth(int width) {
           mTargetView.getLayoutParams().width = width;
           /*重新绘制View的方法*/
           mTargetView.requestLayout();
       } 
   }
   
复制代码

代码中的使用

   //使用的代码
    ViewWrapper wrapper = new ViewWrapper();
    wrapper.setTargetView(view);
    ObjectAnimator.ofInt(wrapper, "width", 0, 500).setDuration(1000).start();
复制代码

上面注释已经写的很详细了,说下大体的思路,传入一个View并通过LayoutParams设置相应的宽高,这样就相当于变相的设置了View的宽高了


关于动画的内容平时开发的时候就总结这么多,还有很多细节没有讲解到,文章写的也比较乱,希望大家不要介意,毕竟我不是文科毕业!我语文分数也不高!!!不好意思了,如果你遇到什么不理解的,可以给我留言。我看到的一定帮你解决!哈哈 ,今天就到这里吧!拜拜。。。

分类:
Android