Android动画教程之属性动画详解

简介

Android 开发中,总是需要一些动画来优化用户的交互体验,提高用户满意度。因此,Google 为我们提供了一些用于处理动画效果的动画框架。Android 的动画框架分为两类:

  • 传统动画(Animation):通过系统不断调用onDraw方法重绘界面,来达到动画的效果。
  • 属性动画(Animator):通过操纵一个属性的get/set方法,真实地改变目标的某些属性。

传统动画框架的局限性

既然有了传统动画框架,Google 为什么还要创造一个属性动画框架呢?

我们下面举个例子来说明一下传统动画的局限性。

在布局中加入一个 ImageView 和一个 Button,点击 ImageView 后弹出一个 Toast,点击 Button 后使 ImageView 展现一个向右平移的动画效果。

下面是使用传统动画实现的代码:

TranslateAnimation animation = new TranslateAnimation(0,200,0,0); // 平移动画x轴移动200,y轴不动
animation.setDuration(1000); // 动画时长
animation.setFillAfter(true); // 使动画结束后停留在结束的位置
mIvPicture.startAnimation(animation);

运行后,ImageView 确实进行了我们预期的平移的效果。可是当我们尝试点击 ImageView 当前的位置时,却没有 Toast 弹出。我们再尝试去点击 ImageView 开始动画前的位置,却成功弹出了 Toast。

这就是传统动画很大的局限性:

  • 它仅仅是重绘了控件,改变了其显示的位置。但真正事件响应的位置,却并没有发生改变。因此传统动画不适合做具有交互的动画效果。仅仅能做一些显示的动画效果。
  • 传统动画是不断通过 onDraw() 方法重绘界面,必然会十分耗费GPU资源。
  • 传统动画所支持的动画类型少,仅有旋转、缩放、位移、透明度这四种动画效果。虽然通过组合可以实现丰富的效果,但相比直接通过改变属性来实现的属性动画来说,还是有很大的局限性的。

因此,Google 为我们提供了一套全新的属性动画框架,来让我们实现更丰富的动画效果。

ObjectAnimator

ObjectAnimator 是属性动画中,最简单也最常用的一个对象。

实现 Animation 框架的功能

平移

前文提到的使 ImageVIew 向右平移 200 像素的动画效果,使用属性动画只需要很简单的几句代码即可实现:

ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F)
 .setDuration(1000)
 .start();

我们来分析一下这一句代码。我们调用了ofFloat代码,并传入三个参数。

​ 第一个参数是动画需要操纵的目标,在这里是我们的 ImageView。

​ 第二个参数是所需要操纵的目标所具备的属性名称。

​ 第三个参数是这个动画变化的取值范围。

最后设置一下它的动画的属性,便可以 start 了。

这次我们再次点击 ImageView 目前的位置,成功地弹出了 Toast。这证实了属性动画是通过改变物体的属性来达到动画效果的理论。

当我们需要改变 y 坐标时,只需要把 "translationX" 变为 "translationY" 即可。

其实 ,只要Google对一个对象的某个属性提供了get和set方法,我们就可以使用这个属性来实现动画效果。

其实我们还能用 X Y 两个属性实现之前的动画效果,那么对象属性中 X 的 Y 与 translationX translationY 有什么区别呢?

translationX translationY指的是物体的偏移量,而X Y则表示它最终到达的绝对位置。

旋转

旋转属性使用的是 "rotation" 属性,后面的变换范围的单位是角度。

比如想让 ImageView 旋转90度,只需要

ObjectAnimator.ofFloat(mIvPicture,"rotation",0F,90F)
 .setDuration(1000)
 .start();

其他

其实属性动画能操纵的属性,只要具有 set、get 方法,都可以进行操纵。如 scaleX、scaleY 等等...

插值器

Android 为我们内置了插值器,使我们的动画更为自然。比如可以让我们的平移动画像物体的重力加速度由快到慢的 Accelerate 等等

Android中内置了七种插值器,分别是

  • Accelerate
  • Decelerate
  • Accelerate/Decelerate
  • Anticipate
  • Overshoot
  • Anticipate/Overshoot
  • Bounce

要应用插值器,可以调用 ObjectAnimator 的 setInterpolator 方法, new 出对应的插值器作为参数(xxxInterpolator)。比如下面这段代码:

animator.setInterpolator(new AccelerateInterpolator());

通过插值器,我们可以让动画的效果更佳自然。

多种属性动画同时作用

当我们把几种动画按顺序写下时,运行程序,会发现效果是三种属性动画的叠加。由此可以发现,属性动画在调用 start 方法后,实际上是一个异步的过程。因此我们就可以看到三个属性动画同时作用的效果。通过这样的方法,其实就可以实现多种属性动画同时作用的效果:

ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F).setDuration(1000).start();
ObjectAnimator.ofFloat(mIvPicture,"rotationX",0F,360F).setDuration(1000).start();
ObjectAnimator.ofFloat(mIvPicture,"translationY",0F,200F).setDuration(1000).start();

其实 Google 为我们提供了更好的方法,来实现这样的效果。

我们可以使用 PropertyValuesHolder 来实现。其构造函数仅仅比 ObjectAnimator 少了一个作用对象参数。之后通过ObjectAnimator 的 ofPropertyValuesHolder 方法,传入作用对象以及要同时作用的 PropertyValuesHolder 即可执行。可以看到下面的代码示例:

PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0F,200F);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("rotationX",0F,360F);
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("translationY",0F,200F);
ObjectAnimator.ofPropertyValuesHolder(mIvPicture,p1,p2,p3).setDuration(1000).start();

运行后可以发现,与之前的效果是相同的。

那既然两种方法效果一样,这样相比之前有什么好处么?

  • 其实 Google 在 PropertyValuesHolder 内部进行了一些优化,使得我们使用多个属性动画时更加有效率,节省系统资源。

AnimatorSet 属性集合

playTogether 方法

我们其实还可以通过 AnimatorSet,来实现同样的效果。这里我们调用了 set 的 playTogether 方法,使得这些方法同时执行:

AnimatorSet set = new AnimatorSet();
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F);
set.playTogether(animator1,animator2,animator3);
set.setDuration(1000);
set.start();

playSequentially方法

除了 playTogether 方法外,AnimatorSet 还提供了 playSequentially 方法,它可以使得动画按顺序执行。具体顺序取决于调用时的参数顺序。

AnimatorSet set = new AnimatorSet();
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F);
set.playSequentially(animator1,animator2,animator3);
set.setDuration(1000);
set.start();

play 与 with、after 方法

我们除了可以用上述方法来让动画按顺序执行外,也可以通过 AnimatorSet 的 play、with、after、before 等方法相组合来控制动画播放关系。

例如如下的代码就可以实现先平移,再旋转的效果

set.play(animator1).with(animator3);
set.play(animator2).after(animator1);

动画监听事件

通过下面的代码,我们可以实现按钮按下后渐隐的效果。

mBtnPress.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
  ObjectAnimator animator = ObjectAnimator.ofFloat(mBtnPress,"alpha",1F,0F);
  animator.setDuration(1000);
  animator.start();
 }
});

但如果我们想要在动画播放完成后再执行一些操作的话,又该如何实现呢?

  • 我们可以使用 ObjectAnimator 的 addListener方法,传入一个AnimatorListener,为动画设置监听事件。

AnimatorListener

一个AnimatorListener,需要实现四个方法,分别是:

  • onAnimationStart
  • onAnimationEnd
  • onAnimationCancel
  • onAnimationRepeat

它们的回调时机我们根据字面意思便可以理解。大部分时候,我们需要实现的是onAnimationEnd方法。

animator.addListener(new AnimatorListener() {
 @Override
 public void onAnimationStart(Animator animation) {
 }
 @Override
 public void onAnimationEnd(Animator animation) {
  Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show();
 }
 @Override
 public void onAnimationCancel(Animator animation) {
 }
 @Override
 public void onAnimationRepeat(Animator animation) {
 }
});

AnimatorListenerAdapter

如果每次监听都需要实现这么多方法,未免太麻烦了一点。因此 Android 为我们提供了另一种方法来添加动画的监听事件:在添加 AnimatorListener 的时候,传入 AnimatorListenerAdapter 即可。这样我们就只需要实现自己需要的方法即可。

animator.addListener(new AnimatorListenerAdapter() {
 @Override
 public void onAnimationEnd(Animator animation) {
  super.onAnimationEnd(animation);
  Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show();
 }
});

ValueAnimator

简介

ValueAnimator 本身不作用于任何一个属性,也不提供任何一种动画。它就是一个数值发生器,可以产生想要的各种数值。Android 系统为它提供了很多计算数值的方法,如 int、float 等等。我们也可以自己实现计算数值的方法。其实,在属性动画中,如何产生每一步的动画效果,都是通过 ValueAnimator 计算出来的。

比如我们要实现一个从 0-100 的位移动画。随着动画时间的持续,它产生的值也会从 0-100 递增。通过这个 ValueAnimator 产生的值,再进行属性的设置即可。

那么 ValueAnimator 究竟是如何产生这些值的呢?

  • 首先 ValueAnimator会根据会根据动画已进行的时间与它持续的总时间的比值,产生一个0-1的时间因子。有了这样的时间因子,经过相应的变换,就可以根据初始值和最终值来生成中间的相应值。同时,通过插值器的使用,我们还可以进一步控制每一个时间因子产生值的变化速率。如果我们使用的是线性插值器,那么它生成值的时候就会呈一个线性变化。如果我们使用一个加速度插值器,那么它生成值时便会呈一个二次曲线,增长率越来越快。

由于 ValueAnimator 不作用于任何一个属性,也不提供任何一种动画。因此并没有 ObjectAnimator 使用得广泛。
实际上,ObjectAnimator 就是基于 ValueAnimator 进行的一次封装。我们可以查看 ObjectAnimator 的源码,会发现它继承自 ValueAnimator,是它的一个子类。正是 ValueAnimator 产生的变化值,才使得 ObjectAnimator 可以将它应用于各个属性。

使用方法

我们可以通过 ValueAnimator 的 ofXXX 产生一个 XXX 类型的值(如ofInt),然后为 ValueAnimator 添加一个更新的回调事件。在回调事件中,通过参数 animation 的 getAnimationValue() 方法,来获取对应的 value。有了这个值,我们就可以实现我们所有想要的动画效果。

比如此处就通过 ValueAnimator 实现了一个计时器的动画效果。

ValueAnimator animator = ValueAnimator.ofInt(0,100);
animator.setDuration(5000);
animator.addUpdateListener(new AnimatorUpdateListener() {
 @Override
 public void onAnimationUpdate(ValueAnimator animation) {
  Integer value = (Integer) animation.getAnimatedValue();
  mButton.setText(""+value);
 }
});
animator.start();

自定义数值生成器

前面提到,ValueAnimator 可以创建自定义的数值生成器,做法就是调用 ValueAnimator 的 ofObject 方法,创建一个 TypeEvaluator 作为参数。之后我们可以通过重写 TypeEvaluator 的 evaluate 方法,来按照自己的规则返回具体的值。

ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() {
 @Override
 public Object evaluate(float fraction, Object startValue, Object endValue) {
  //计算
  return null; //返回值
 }
});

我们来看一下 evaluate 方法的几个参数

  • float fraction:前面提到的时间因子
  • Object startValue:起始值
  • Object endValue:结束值

通过这三个值,我们就可以经过计算产生所有我们想要的值。

其实,通过 TypeEvaluator,我们不光能产生普通的数据,还能结合泛型,我们还能定义更加复杂的数据:

我们可以在创建 TypeEvaluator 时指定具体类型,来达到更丰富的效果。比如这里就用到了一个名为 PointF 的数据类型:

ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
 @Override
 public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
  //计算
  return null; //返回值
 }
});

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • Android 动画(View动画,帧动画,属性动画)详细介绍

    0. 前言  Android动画是面试的时候经常被问到的话题.我们都知道Android动画分为三类:View动画.帧动画和属性动画. 先对这三种动画做一个概述: View动画是一种渐进式动画,通过图像的平移.缩放.旋转和透明度等各种渐进式变换完成动画效果. 帧动画是通过不停的切换图片实现动画效果. 属性动画是不停的改变对象的属性来实现动画效果.本文原创,转载请注明出处: http://blog.csdn.net/seu_calvin/article/details/52724655 1.  Vi

  • Android帧动画、补间动画、属性动画用法详解

    在安卓开发中,经常会使用到一些动画,那么在开发中,如何使用这些动画呢? 帧动画:不是针对View做出一些形状上的变化,而是用于播放一张张的图片,例如一些开机动画,类似于电影播放,使用的是AnimationDrawable来播放帧动画 res/drawable <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.androi

  • Android属性动画实现炫酷的登录界面

    我们聊聊我们常写的登录界面,这个界面我相信很多人都写过,而且也没什么难度,但是如果要实现比较不一般的效果,那就要花点心思了,先看看项目的效果吧: 我一直都不知道怎么在编辑框连设置图片大小,所以这个图不怎么样适配编辑框了,大家先凑合着看看. 我先讲讲思路,当我们输入完账号跟密码之后,点击登录,那这个输入框就慢慢的消失,在消失后,紧接着就出现这个进度的界面. 思路有了,那我们就开始编码了: 新建一个项目,然后系统生成了一个MainActivity.java文件和activity_main.xml文件

  • Android属性动画实现布局的下拉展开效果

    在Android的3.0之后,google又提出了属性动画的这样一个框架,他可以更好的帮助我们实现更丰富的动画效果.所以为了跟上技术的步伐,今天就聊一聊属性动画. 这一次的需求是这样的:当点击一个View的时候,显示下面隐藏的一个View,要实现这个功能,需要将V iew的visibility属性设置gone为visible即可,但是这个过程是一瞬间的,并不能实现我们要的效果.所以,属性动画是个不错的方案. 先把效果贴上 第一个:  第二个: 前面的这个是隐藏着,后面这个是显示的.当点击这个箭头

  • Android动画 实现开关按钮动画(属性动画之平移动画)实例代码

    Android动画 实现开关按钮动画(属性动画之平移动画),最近做项目,根据项目需求,有一个这样的功能,实现类似开关的动画效果,经过自己琢磨及上网查找资料,终于解决了,这里就记录下: 在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率.另外说到动画,在Android里面支持3种动画: 逐帧动画(Frame Animation).补间动画(Tween Animation)和属性动画(Property Animation),至于这

  • 图文详解Android属性动画

    Android中的动画分为视图动画(View Animation).属性动画(Property Animation)以及Drawable动画.从Android 3.0(API Level 11)开始,Android开始支持属性动画,本文主要讲解如何使用属性动画.关于视图动画可以参见博文<Android四大视图动画图文详解>. 一.概述 视图动画局限比较大,如下所述: 1.视图动画只能使用在View上面. 2.视图动画并没有真正改变View相应的属性值,这导致了UI效果与实际View状态存在差异

  • Android中编写属性动画PropertyAnimation的进阶实例

    0.基础回顾 PropertyAnimation,属性动画,顾名思义就是利用对象的属性变化形成动画的效果.属性动画的类可以用Animator这个抽象类来表示,通常使用它的子类:AnimatorSet和ValueAnimator,同时ValueAnimator有两个子类分别是ObjectAniamtor和TimeAnimator. 定义属性动画的XML资源的时候通常可以是如下三个元素之一作为根元素: <set>元素:该资源元素代表的是AniamtorSet类,这个类可以包含<set>

  • Android 属性动画ValueAnimator与插值器详解

    Android 属性动画ValueAnimator与插值器详解 一.ValueAnimator详解: ValueAnimator是整个动画的核心,ObjectAnimator即是继承自ValueAnimator来实现. ValueAnimator更像是一个数值发生器,用来产生具有一定规律的数字,从而让调动者来控制动画的实现过程. 1.ValueAnimator的使用: ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); val

  • Android模拟开关按钮点击打开动画(属性动画之平移动画)

    在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率.另外说到动画,在Android里面支持两种动画:补间动画和属性动画,至于这两种动画的区别这里不再介绍,希望开发者都能在使用的过程中体会两者的不同. 本文使用属性动画完成,说到属性动画,肯定要提到 JakeWharton大神写的NineOldAndroids动画库,如果你的app需要在android3.0以下使用属性动画,那么这个库就很有作用了,如果只需要在高版本使用,那么直接

  • Android 自定义view和属性动画实现充电进度条效果

    近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和自定义view的方式来完成这个功能,将它开源出来,供有需要的人了解一下相关的内容. 本次实现的功能类似下面的效果: 接下来便详细解析一下如何完成这个功能,了解其中的原理,这样就能举一反三,实现其他类似的动画效果了. 详细代码请看大屏幕 https://github.com/crazyandcoder

随机推荐