Android 基础动画之属性动画详解

简介: 在上两篇文章主要介绍了 Android 基础动画之帧动画 以及 Android 基础动画之补间动画 。本篇文章主要介绍的是Android基础动画之 属性动画 。

在上两篇文章主要介绍了 Android 基础动画之帧动画 以及 Android 基础动画之补间动画 。本篇文章主要介绍的是Android基础动画之 属性动画

补间动画 这篇文章的末尾有说道,补间动画执行完毕以后,加载的view实际上是没有点击事件的,因为点击事件依旧附着在原来的view位置,所以这种动画的完整体验有点蜜汁尴尬。为了解决这种设计之初带来的体验问题,Android3.0以后开始引入属性动画来完美解决这一历史遗留问题。

属性动画的强大之处在于,它可以作用到任何对象(不仅仅针对视图View对象),另外,属性动画还可以自定义各种动画效果(不仅仅是平移、旋转、缩放、透明度的变化)。那么属性动画是如何做到这些功能的?它的原理是在一定时间内,不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。

说完了属性动画的作用和优点,下面就用代码去学习掌握属性动画。其中属性动画有两个非常重要的类:分别是ValueAnimator 类、ObjectAnimator 类。

ObjectAnimator:

ObjectAnimator简单理解是直接对对象的属性值进行改变操作,从而实现动画效果。ObjectAnimator本质是通过不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果。ObjectAnimator一般推荐是代码进行使用(下面是基本代码和一些常见的API):

        //目标view  
        TextView mTextView = findViewById(R.id.ob_text);

        //平移动画
        ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTextView, "translationX", 200);
        
        // 设置动画运行的时长
        translationAnimator.setDuration(500);

        // 设置动画延迟播放时间
        translationAnimator.setStartDelay(500);

        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复
        translationAnimator.setRepeatCount(0);

        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        translationAnimator.setRepeatMode(ValueAnimator.RESTART);

        //开始动画
        translationAnimator.start();

        //旋转动画
        ObjectAnimator rotation = ObjectAnimator.ofFloat(mTextView,"rotation",90);
        rotation.setDuration(500);
        rotation.start();

        //缩放动画
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(mTextView,"scaleX",1.5f);
        scaleX.setDuration(500);
        scaleX.start();

        //透明度动画
        ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextView,"alpha",0.2f);
        alpha.setDuration(500);
        alpha.start();
        

你可能会问,那我想通过ObjectAnimator来同时实现多个效果一起运行,那该怎么办?
如果想通过一个ObjectAnimator同时改变多个属性,则需要使用PropertyValuesHolder,参考代码如下:


        PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX",200);
        PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("translationY",200) ;
        PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("rotation",90) ;
        PropertyValuesHolder holder4 = PropertyValuesHolder.ofFloat("scaleX",1.5f) ;
        PropertyValuesHolder holder5 = PropertyValuesHolder.ofFloat("alpha",0.2f) ;

        //ObjectAnimator.ofPropertyValuesHolder()
        //参数一:目标view
        //参数二:可变参数 支持多个PropertyValuesHolder
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, holder1, holder2,holder3,holder4,holder5);
        
        animator.setDuration(500);
        
        animator.start();

下面在来看看ValueAnimator

ValueAnimator

ValueAnimator实现动画的原理是通过不断控制值的变化,然后手动赋给对象的属性,从而实现动画效果。ValueAnimator的大致流程是,先指定将初始值以何种数值(整型、浮点型)的形式 过渡到结束值;接着,开发者手动将值,赋值给目标的属性值。接下来的步伐涉及到了别的内容(插值器与估值器)但还是会慢慢分析。

ValueAnimator重要的方法我基于面向对象的设计原则将其分为两类三个(本质是一类),当然这是我自己的理解。既然是面向对象的设计语言,那么第一步肯定是 new 对象,那么ValueAnimator这个类 new 对象的第一种姿势是这样的:

        /**
         * ValueAnimator创建对象姿势一:
         * 调用ofInt(int...)、ofFloat(float...)
         * 形参是可变参数、可传多个参数
         * 将传入的多个Int参数进行平滑过渡:假设此处传入0和3,表示将值从0平滑过渡到3
         * 以此类推如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,
         */
        ValueAnimator animInt = ValueAnimator.ofInt(0, 3);

        ValueAnimator animFoat = ValueAnimator.ofFloat(0, 3);

既然拿到了ValueAnimator实例对象以后,接下来就调用对象提供的方法实现具体的功能( 下面是参考代码 )

        textView = findViewById(R.id.ob_text);

        ValueAnimator animInt = ValueAnimator.ofInt(0, 3);

        // 设置动画运行的时长
        animInt.setDuration(500);

        // 设置动画延迟播放时间
        animInt.setStartDelay(500);

        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复
        animInt.setRepeatCount(0);

        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        animInt.setRepeatMode(ValueAnimator.RESTART);

        animInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                float value = (float) animation.getAnimatedValue();
                Log.i("app","属性值:"+"fraction:"+fraction+",value:"+value);

                //在这里设置具体的动画属性值
                textView.setTranslationX(value);

            }
        });

        //开启动画
        animInt.start();

说完了第一种new ValueAnimator对象的姿势,现在说第二种:


        /**
         * ValueAnimator实例化对象姿势二:
         * 参数一:TypeEvaluator 估值器
         * 参数二:Object... values 可变参数,可以传入具体的动画对象(开始-结束)
         */

        ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator() {
            @Override
            public Object evaluate(float fraction, Object startValue, Object endValue) {
                return null;
            }
        },"","");
        

可以看到,通过ofObject这个函数实例化ValueAnimator对象的时候,需要我们传入一个TypeEvaluator,
以及一个可变参数Object,下面就这2个参数着重说明:

参数一:TypeEvaluator(估值器)

这个就是我们经常提到的估值器。估值器和插值器是很多开发容易搞混淆的一个概念,面试的时候也会问到这个(因为自定义控件会附加动画的内容)本着不抛弃不放弃的精神、下面就对这两个概念进行详尽分析:

首先,这个TypeEvaluator(估值器)本质是一个接口,源码如下:


public interface TypeEvaluator<T> {

    /**
     * This function returns the result of linearly interpolating the start and end values,with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value.
     * @param endValue   The end value.
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
     
    public T evaluate(float fraction, T startValue, T endValue);

}

其实,通过源码的英文注释就可以分析出这个估值器的实际作用(英文注释翻译过来就是):这个函数返回线性插值起始值和结束值的结果。其中参数fraction代表起始值和结束值之间的比例。简单的计算公式是:result = x0 + t * (x1 - x0);参数的具体是指:x0=startValue;x1=endValue;t=fraction最后,这个方法返回的是,在开始和结束值之间的线性插值,给定分数参数。

简单点说就是,估值器是通过计算公式来进行的值的计算。

还有一点,之前说的ValueAnimator.ofFloat()以及ValueAnimator.ofInt(),这2个方法内部实际上由系统已经设置好了对应的估值器,分别是FloatEvaluator以及IntEvaluator,所以虽然是“两类三个”,但本质上来说还是属于"一类"。

另外既然我们知道了计算公式、那么就可以根据业务定制自己的估值器,下面是参考拓展代码:

    /**
     * TypeEvaluator里面的泛型可以根据业务去订制
     */
    class MyEvaluator implements TypeEvaluator<Object>{

        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            /**
             * 计算公式自己随意拓展
             */
            return null;
        }
    }

接着将这个自定义的估值器设置到我们的ValueAnimator即可:

 ValueAnimator valueAnimator = ValueAnimator.ofObject(new MyEvaluator());

说完了TypeEvaluator我们在来看看插值器:Interpolator:

Interpolator(插值器)

依旧打开源码目睹下庐山真面目:

/**
 * An interpolator defines the rate of change of an animation. This allows
 * the basic animation effects (alpha, scale, translate, rotate) to be 
 * accelerated, decelerated, repeated, etc.
 */
public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

嗯,英文注释非常详细,首先是类注释,翻译过来如下:差值器定义了动画的变化速率。这允许基本的动画(透明、缩放、平移、旋转)效果可以加速,减速,重复,等等。关于接口方法内的注释主要是关于新旧版本TimeInterpolator的一些说明。

另外,笔者的Android SDK系统版本是26,所以源码可能会有一些不同。

透过英文注释可以得知:插值器的功能主要是为了丰富(透明、缩放、平移、旋转)这些动画的效果。比如,我们可以通过插值器去设置炫丽的效果,让以往的动画生冷平稳的过渡效果成为历史,让动画变的更立体、更有灵魂。也就是让动画效果变化的模式更客观

系统也为我们提供了一些默认的插值器方便我们使用:


img_b3680ec4de435941c338fafc5808610e.png
插值器

那么,如何使用系统为我们提供好的插值器?声明一个插值器有两种写法:

  • 写法一:通过xml文件,对标签的内容进行编写

首先: res/animator的文件夹路径内里创建相应的动画xml

接着:代码编写

<animator xmlns:android="http://schemas.android.com/apk/res/android"  

    // 初始值
    android:valueFrom="0" 
    
    // 结束值
    android:valueTo="100"  
    
    // 变化值类型 :floatType & intType
    android:valueType="intType" 

    // 动画持续时间(ms),必须设置,动画才有效果
    android:duration="3000" 

    // 动画延迟开始时间(ms)
    android:startOffset ="1000"
    
    // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
    android:fillBefore = “true” 
    
    // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
    android:fillAfter = “false” 
    
    // 是否应用fillBefore值,对fillAfter值无影响,默认为true
    android:fillEnabled= “true” 
    
    // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
    android:repeatMode= “restart” 

    // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
    android:repeatCount = “0” 

    // 插值器  这里等价于OvershootInterpolator
    android:interpolator = "@android:anim/overshoot_interpolator"

/>

其中,这里的 android:interpolator 标签代表的就是Java中的OvershootInterpolator这个系统为我们写好的插值器

  • 写法二:Java代码编写
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new MyEvaluator());

        Animation animation = new AlphaAnimation(1,0);
        //调用setInterpolator 使用插值器
        animation.setInterpolator(new OvershootInterpolator());

那系统自带的插值器代表的意思是什么?

Interpolator 资源ID 功能
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 先加速再减速
AccelerateInterpolator @android:anim/accelerate_interpolator 加速
AnticipateInterpolator @android:anim/anticipate_interpolator 先后退一小步然后加速前进
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 先后退一小步再加速前进,超出终点一小步再回到终点
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 快速到达终点并超出一小步然后回到终点

嗯,以上九个插值器所带来的各种效果是很丰富的(比如,最后一个阶段有弹球的效果;或者先加速再减速),很多博客和资料也是说的是九个。如果你细心看完上面那张系统父子关系层级截图,你会发现系统明明为我们生成了10个默认的插值器,但是你这里只有9个?难道是写漏了一个?嗯,多余的一个是PathInterpolator

打开PathInterpolator源码可以看到它的两个构造函数,生成的path其实是一个贝赛尔曲线。有兴趣的小伙伴可以自行查阅资料去了解该插值器的使用和说明。

回到正题,一般来说,系统为我们提供的插值器基本上就可以满足开发需求了,如果还是不能满足我们就可以自定义插值器:

 class MyInterpolator implements Interpolator{

        @Override
        public float getInterpolation(float input) {
            /**
             * 在这里做自己想要做的逻辑
             */
            return 0;
        }
    }

关于自定义插值器里面的getInterpolation(float input)这个方法需要说明一下,这里的input的取值范围是0 - 1,另外,在这个方法内部我们就可以根据业务进行自己想要的计算。

总结:

属性动画是Android3.0之后出现的动画,不仅解决了之前的历史遗留问题,而且通过搭配估值器与插值器的效果让我们的动画更加立体形象、丰富多彩。

如果这篇文章对你有帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果

相关文章
|
7月前
|
Android开发 开发者
Android利用SVG实现动画效果
本文介绍了如何在Android中利用SVG实现动画效果。首先通过定义`pathData`参数(如M、L、Z等)绘制一个简单的三角形SVG图形,然后借助`objectAnimator`实现动态的线条绘制动画。文章详细讲解了从配置`build.gradle`支持VectorDrawable,到创建动画文件、关联SVG与动画,最后在Activity中启动动画的完整流程。此外,还提供了SVG绘制原理及工具推荐,帮助开发者更好地理解和应用SVG动画技术。
318 30
|
7月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
527 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
7月前
|
API Android开发 开发者
Android颜色渐变动画效果的实现
本文介绍了在Android中实现颜色渐变动画效果的方法,重点讲解了插值器(TypeEvaluator)的使用与自定义。通过Android自带的颜色插值器ArgbEvaluator,可以轻松实现背景色的渐变动画。文章详细分析了ArgbEvaluator的核心代码,并演示了如何利用Color.colorToHSV和Color.HSVToColor方法自定义颜色插值器MyColorEvaluator。最后提供了完整的源码示例,包括ColorGradient视图类和MyColorEvaluator类,帮助开发者更好地理解和应用颜色渐变动画技术。
230 3
|
7月前
|
Android开发 开发者
Android SVG动画详细例子
本文详细讲解了在Android中利用SVG实现动画效果的方法,通过具体例子帮助开发者更好地理解和应用SVG动画。文章首先展示了动画的实现效果,接着回顾了之前的文章链接及常见问题(如属性名大小写错误)。核心内容包括:1) 使用阿里图库获取SVG图形;2) 借助工具将SVG转换为VectorDrawable;3) 为每个路径添加动画绑定属性;4) 创建动画文件并关联SVG;5) 在ImageView中引用动画文件;6) 在Activity中启动动画。文末还提供了完整的代码示例和源码下载链接,方便读者实践操作。
348 65
|
7月前
|
XML Java Maven
Android线条等待动画JMWorkProgress(可添加依赖直接使用)
这是一篇关于Android线条等待动画JMWorkProgress的教程文章,作者计蒙将其代码开源至GitHub,提升可读性。文章介绍了如何通过添加依赖库使用该动画,并详细讲解了XML与Java中的配置方法,包括改变线条颜色、宽度、添加文字等自定义属性。项目已支持直接依赖集成(`implementation &#39;com.github.Yufseven:JMWorkProgress:v1.0&#39;`),开发者可以快速上手实现炫酷的等待动画效果。文末附有GitHub项目地址,欢迎访问并点赞支持!
212 26
|
7月前
|
XML Android开发 数据格式
Android中SlidingDrawer利用透明动画提示效果
本文介绍了在Android中使用`SlidingDrawer`实现带有透明动画提示效果的方法。通过XML布局配置`SlidingDrawer`的把手(handle)和内容(content),结合Activity中的代码实现动态动画效果。最终实现了交互性强、视觉效果良好的滑动抽屉功能。
Android中SlidingDrawer利用透明动画提示效果
|
7月前
|
XML Java Android开发
Android 动画之帧动画 + 补间动画 + 属性动画
本文介绍了Android开发中的三种动画类型:帧动画、补间动画和属性动画。帧动画通过依次播放一系列静态图片实现动态效果,支持Java代码与XML两种实现方式。补间动画基于起始和结束位置自动生成过渡效果,涵盖透明度、位移、旋转、缩放及组合动画等多种形式,并可搭配插值器优化动画过程。属性动画则通过改变对象属性实现动画,支持透明度、位移、旋转、缩放及组合动画,灵活性更高且适用于更复杂的场景。文中提供了详细的代码示例,帮助开发者快速上手。
393 15
|
7月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
134 0
Android自定义view之围棋动画(化繁为简)
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
576 2
基于Android P,自定义Android开机动画的方法