一、简单属性动画

1.1 通过 xml 实现动画

基本的属性介绍:
在res/animator文件夹下,创建animator_translation.xml文件。XML文件有四个标签可用,要注意到propertyValuesHolder标签的Android 版本适配。

set标签对应代码的AnimatorSet,只有一个属性可以设置:android:ordering,取值:同时播放together、顺序播放sequentially
animator标签对应代码的ValueAnimator,可以设置如下属性:

  • android:duration:动画时长
  • android:valueType:属性类型,intTypefloatTypecolorTypepathType
  • android:valueFrom:属性初始值
  • android:valueTo:属性结束值
  • android:repeatCount:重复次数
  • android:repeatMode:重复模式
  • android:interpolator:插值器,可看下一节默认插值器。
  • android:startOffset:延迟,对应startOffset()延迟多少毫秒执行

调用:

  1. val alpha = AnimatorInflater.loadAnimator(this, R.animator.alpha_test)
  2. alpha.setTarget(tv_property_anim)
  3. alpha.start()

注意属性名不能写错,全部属性名如下:

  1. const val ALPHA = "alpha"
  2. const val SCALE_X = "scaleX"
  3. const val SCALE_Y = "scaleY"
  4. const val ROTATION = "rotation"
  5. const val ROTATION_X = "rotationX"
  6. const val ROTATION_Y = "rotationY"
  7. const val TRANSLATION_X = "translationX"
  8. const val TRANSLATION_Y = "translationY"

示例:

    1. 渐变 ```java <?xml version=”1.0” encoding=”utf-8”?>

  1. - 2. 旋转
  2. ```java
  3. <?xml version="1.0" encoding="utf-8"?>
  4. <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:propertyName="rotation"
  6. android:valueFrom="0"
  7. android:valueTo="180"
  8. android:duration="2000"
  9. android:valueType="floatType">
  10. </objectAnimator>
    1. 平移 ```java <?xml version=”1.0” encoding=”utf-8”?>

  1. - 4. 缩放
  2. ```java
  3. <?xml version="1.0" encoding="utf-8"?>
  4. <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:propertyName="scaleX"
  6. android:valueFrom="1"
  7. android:valueTo="2"
  8. android:duration="2000"
  9. android:valueType="floatType"
  10. >
  11. </objectAnimator>
    1. 动画集合

      1. <?xml version="1.0" encoding="utf-8"?>
      2. <set xmlns:android="http://schemas.android.com/apk/res/android"
      3. >
      4. <objectAnimator android:duration="3000"
      5. android:propertyName="alpha"
      6. android:valueFrom="0.2"
      7. android:valueTo="1"/>
      8. <objectAnimator android:duration="3000"
      9. android:propertyName="scaleX"
      10. android:valueFrom="1"
      11. android:valueTo="2"/>
      12. </set>

      1.2 通过代码实现

      顾名思义,通过控制对象的属性,来实现动画效果。官方定义:定义一个随着时间 (注:停个顿)更改任何对象属性的动画,无论其是否绘制到屏幕上。
      可以控制对象什么属性呢?什么属性都可以,理论是通过set和get某个属性来达到动画效果。例如常用下面一些属性来实现View对象的一些动画效果。

位移:translationX、translationY、translationZ
透明度:alpha,透明度全透明到不透明:0f->1f
旋转:rotation,旋转一圈:0f->360f
缩放:水平缩放scaleX,垂直缩放scaleY

简单的效果图:
属性动画 - 图1

  • 1. 位移动画

先看一下布局代码的实现:

  1. <LinearLayout
  2. android:id="@+id/llAddAccount"
  3. android:layout_width="wrap_content"
  4. android:layout_height="35dp"
  5. android:layout_alignParentRight="true"
  6. android:layout_marginTop="100dp"
  7. android:layout_marginRight="-70dp"//将现有视图藏在屏幕的右边
  8. android:background="@drawable/bg_10_10_fff">
  9. <ImageView
  10. android:id="@+id/ivMakeNote"
  11. android:layout_width="35dp"
  12. android:layout_height="30dp"
  13. android:layout_gravity="center_vertical"
  14. android:paddingLeft="2dp"
  15. android:paddingTop="2dp"
  16. android:paddingBottom="2dp"
  17. android:src="@mipmap/ic_account_add" />
  18. <TextView
  19. android:id="@+id/tvAddAccount"
  20. android:layout_width="wrap_content"
  21. android:layout_height="match_parent"
  22. android:gravity="center_vertical"
  23. android:paddingRight="12dp"
  24. android:text="添加账户"
  25. android:textColor="@color/colorPrimary"
  26. android:textSize="14sp" />
  27. </LinearLayout>

上面只是简单实现了布局,下面看看属性动画代码的实现:

  1. llAddAccount.setOnClickListener {
  2. val objectAnimation =ObjectAnimator.ofFloat(llAddAccount, "translationX", 0f, -70f)
  3. objectAnimation.start()
  4. }

到这里,我们才真正看到属性动画的影子。通过ObjectAnimator的工厂方法ofFloat我们得到一个ObjectAnimator对象,并通过该对象的start()方法,开启动画效果。

ofFloat()方法的第一个参数为要实现动画效果的View,例如这里整体效果的LinearLayout;第二个参数为属性名,也就是前面所说的:translationX,translationY,alpha,rotation,scaleX,scaleY等,这里要实现的是水平平移效果,所以我们采用了translationX;第三参数为可变长参数,第一个值为动画开始的位置,第二个值为结束值得位置,如果数组大于3位数,那么前者将是后者的起始位置。

注意事项:如果可变长参数只有一个值,那么ObjectAnimator的工厂方法会将值作为动画结束值,此时属性必须拥有初始化值和getXXX方法。

translationX和translationY这里涉及到的位移都是相对自身位置而言。例如 View在点A(x,y)要移动到点B(x1,y1),那么ofFloat()方法的可变长参数,第一个值应该0f,第二个值应该x1-x。

XML布局实现:
在res/animator文件夹下,创建animator_translation.xml文件,内容如下:

在代码上调用:

  1. llAddAccount.setOnClickListener {
  2. val objectAnimation =AnimatorInflater.loadAnimator(this,R.animator.animator_translation)
  3. objectAnimation.setTarget(llAddAccount)
  4. objectAnimation.start()
  5. }
  • 2、透明属性动画

透明度属性动画比较简单,即控制View的可见度实现视觉差动画效果。这里展示效果是从不透明到透明,再到不透明。
属性动画 - 图2

代码如下:

  1. tvText.setOnClickListener {
  2. val objectAnimation =ObjectAnimator.ofFloat(tvText, "alpha", 1f,0f,1f)
  3. objectAnimation.duration=3000
  4. objectAnimation.start()
  5. }

ofFloat()方法将属性名换成了透明度alpha,并且可变长参数增加到了3个。给ObjectAnimator对象的duration属性设置了动画展示时间3秒,默认情况下300毫秒。

  • 3、缩放属性动画

缩放可以通过控制scaleX和scaleY分别在X轴和Y轴上进行缩放,如下图在X轴中进行两次两倍缩放。
属性动画 - 图3
代码如下:

  1. tvText.setOnClickListener {
  2. val objectAnimation =ObjectAnimator.ofFloat(tvText, "scaleX", 1f,2f)
  3. objectAnimation.duration=3000
  4. objectAnimation.repeatCount=2
  5. objectAnimation.repeatMode=ValueAnimator.REVERSE
  6. objectAnimation.start()
  7. }

ofFloat()方法传入参数属性为scaleX和scaleY时,动态参数表示缩放的倍数。设置ObjectAnimator对象的repeatCount属性来控制动画执行的次数,设置为ValueAnimator.INFINITE表示无限循环播放动画;通过repeatMode属性设置动画重复执行的效果,取值为:ValueAnimator.RESTART和ValueAnimator.REVERSE。
ValueAnimator.RESTART效果:(即每次都重头开始)
属性动画 - 图4

ValueAnimator.REVERSE效果:(即和上一次效果反着来)
属性动画 - 图5

  • 4、旋转属性动画

旋转动画也比较简单,将一个View进行顺时针或逆时针旋转。
属性动画 - 图6

代码如下:

  1. tvText.setOnClickListener {
  2. val objectAnimation =
  3. ObjectAnimator.ofFloat(tvText, "rotation", 0f,180f,0f)
  4. objectAnimation.duration=3000
  5. objectAnimation.start()
  6. }

ofFloat()方法的可变长参数,如果后者的值大于前者,那么顺时针旋转,小于前者,则逆时针旋转。

  • 5、AnimatorSet

如果想要一个动画结束后播放另外一个动画,或者同时播放,可以通过AnimatorSet来编排。

  1. val aAnimator=ObjectAnimator.ofInt(1)
  2. val bAnimator=ObjectAnimator.ofInt(1)
  3. val cAnimator=ObjectAnimator.ofInt(1)
  4. val dAnimator=ObjectAnimator.ofInt(1)
  5. AnimatorSet().apply {
  6. play(aAnimator).before(bAnimator)//a 在b之前播放
  7. play(bAnimator).with(cAnimator)//b和c同时播放动画效果
  8. play(dAnimator).after(cAnimator)//d 在c播放结束之后播放
  9. start()
  10. }

或者

  1. AnimatorSet().apply {
  2. playSequentially(aAnimator,bAnimator,cAnimator,dAnimator) //顺序播放
  3. start()
  4. }
  5. AnimatorSet().apply {
  6. playTogether(animator,bAnimator,cAnimator,dAnimator) //同时播放
  7. start()
  8. }

另有:

  1. AnimatorSet ().apply {
  2. play(aAnimator).after(1000) //1秒后播放a动画
  3. start()
  4. }

二、设置旋转或是平移中心

只能通过要设置动画的控件来设置,无论是 xml 还是代码实现动画都是这样,示例:

  1. val rotateZ = AnimatorInflater.loadAnimator(this, R.animator.rorate_x)
  2. //设置中心
  3. tv_property_anim.pivotX = 0f
  4. tv_property_anim.pivotY = 0f
  5. tv_property_anim.invalidate()
  6. rotateZ.setTarget(tv_property_anim)
  7. rotateZ.start()

三、实现一个控件多个动画

    1. 使用 ValueAnimator
      1. val valueAnimator = ValueAnimator.ofFloat(0f, 500f)
      2. valueAnimator.setTarget(tv_property_anim)
      3. valueAnimator.duration = 1000
      4. valueAnimator.start()
      5. valueAnimator.addUpdateListener {
      6. tv_property_anim.translationY = it.animatedValue as Float
      7. }
      使用 ValueAnimator 改变控件的宽高:
      1. private fun testValueAnimatorAnim() {
      2. val width2 = tv_property_anim.layoutParams.width
      3. val width = tv_property_anim.width
      4. LogUtils.e("$width----- $width2")
      5. val valueAnimator = ValueAnimator.ofInt(width, width * 2)
      6. valueAnimator.duration = 2000
      7. valueAnimator.addUpdateListener {
      8. //当前值
      9. LogUtils.e(it.animatedValue)
      10. tv_property_anim.layoutParams.width = it.animatedValue as Int
      11. //刷新视图,即重新绘制,从而实现动画效果
      12. tv_property_anim.requestLayout()
      13. }
      14. valueAnimator.start()
      15. }
    1. ObjectAnimator
      1. val anim = ObjectAnimator.ofFloat(
      2. tv_property_anim,
      3. "AnimatorUtil.SCALE_X",
      4. 1f, 0f
      5. ).setDuration(2000)
      6. anim.start()
      7. anim.addUpdateListener {
      8. val fl = it.animatedValue as Float
      9. tv_property_anim.alpha = fl
      10. tv_property_anim.scaleX = fl
      11. tv_property_anim.scaleY = fl
      12. }
    1. PropertyValuesHolder
      1. btn_property_propertyValuesHolder.setOnClickListener {
      2. val alpha = PropertyValuesHolder.ofFloat(AnimatorUtil.ALPHA, 1f, 0f, 1f)
      3. val scalex = PropertyValuesHolder.ofFloat(AnimatorUtil.SCALE_X, 1f, 0f, 1f)
      4. val scaley = PropertyValuesHolder.ofFloat(AnimatorUtil.SCALE_Y, 1f, 0f, 1f)
      5. ObjectAnimator.ofPropertyValuesHolder(tv_property_anim,alpha,scalex,scaley).setDuration(2000).start()
      6. }
    1. 使用 animtorset
      1. val set = AnimatorSet()
      2. val rotation = ObjectAnimator.ofFloat(tv_property_anim,AnimatorUtil.ROTATION,0f,90f)
      3. val rotationX = ObjectAnimator.ofFloat(tv_property_anim,AnimatorUtil.ROTATION_X,0f,40f)
      4. set.play(rotation).with(rotationX)
      5. set.duration = 2000
      6. set.start()

      四、参考

      Android属性动画,看完这篇够用了吧
      Android中的View动画和属性动画
      Android 属性动画:这是一篇全面 & 详细的 属性动画 总结&攻略
      Android 属性动画(Property Animation) 完全解析
      Android属性动画完全解析