一、简单属性动画
1.1 通过 xml 实现动画
基本的属性介绍:
在res/animator文件夹下,创建animator_translation.xml文件。XML文件有四个标签可用,要注意到propertyValuesHolder标签的Android 版本适配。
set标签对应代码的AnimatorSet,只有一个属性可以设置:android:ordering,取值:同时播放together、顺序播放sequentially。animator标签对应代码的ValueAnimator,可以设置如下属性:
android:duration:动画时长android:valueType:属性类型,intType、floatType、colorType、pathTypeandroid:valueFrom:属性初始值android:valueTo:属性结束值android:repeatCount:重复次数android:repeatMode:重复模式android:interpolator:插值器,可看下一节默认插值器。android:startOffset:延迟,对应startOffset()延迟多少毫秒执行
调用:
val alpha = AnimatorInflater.loadAnimator(this, R.animator.alpha_test)alpha.setTarget(tv_property_anim)alpha.start()
注意属性名不能写错,全部属性名如下:
const val ALPHA = "alpha"const val SCALE_X = "scaleX"const val SCALE_Y = "scaleY"const val ROTATION = "rotation"const val ROTATION_X = "rotationX"const val ROTATION_Y = "rotationY"const val TRANSLATION_X = "translationX"const val TRANSLATION_Y = "translationY"
示例:
- 渐变
```java
<?xml version=”1.0” encoding=”utf-8”?>
- 渐变
```java
<?xml version=”1.0” encoding=”utf-8”?>
- 2. 旋转```java<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:propertyName="rotation"android:valueFrom="0"android:valueTo="180"android:duration="2000"android:valueType="floatType"></objectAnimator>
- 平移
```java
<?xml version=”1.0” encoding=”utf-8”?>
- 平移
```java
<?xml version=”1.0” encoding=”utf-8”?>
- 4. 缩放```java<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:propertyName="scaleX"android:valueFrom="1"android:valueTo="2"android:duration="2000"android:valueType="floatType"></objectAnimator>
动画集合
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimator android:duration="3000"android:propertyName="alpha"android:valueFrom="0.2"android:valueTo="1"/><objectAnimator android:duration="3000"android:propertyName="scaleX"android:valueFrom="1"android:valueTo="2"/></set>
1.2 通过代码实现
顾名思义,通过控制对象的属性,来实现动画效果。官方定义:定义一个随着时间 (注:停个顿)更改任何对象属性的动画,无论其是否绘制到屏幕上。
可以控制对象什么属性呢?什么属性都可以,理论是通过set和get某个属性来达到动画效果。例如常用下面一些属性来实现View对象的一些动画效果。
位移:translationX、translationY、translationZ
透明度:alpha,透明度全透明到不透明:0f->1f
旋转:rotation,旋转一圈:0f->360f
缩放:水平缩放scaleX,垂直缩放scaleY
简单的效果图:
- 1. 位移动画
先看一下布局代码的实现:
<LinearLayoutandroid:id="@+id/llAddAccount"android:layout_width="wrap_content"android:layout_height="35dp"android:layout_alignParentRight="true"android:layout_marginTop="100dp"android:layout_marginRight="-70dp"//将现有视图藏在屏幕的右边android:background="@drawable/bg_10_10_fff"><ImageViewandroid:id="@+id/ivMakeNote"android:layout_width="35dp"android:layout_height="30dp"android:layout_gravity="center_vertical"android:paddingLeft="2dp"android:paddingTop="2dp"android:paddingBottom="2dp"android:src="@mipmap/ic_account_add" /><TextViewandroid:id="@+id/tvAddAccount"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"android:paddingRight="12dp"android:text="添加账户"android:textColor="@color/colorPrimary"android:textSize="14sp" /></LinearLayout>
上面只是简单实现了布局,下面看看属性动画代码的实现:
llAddAccount.setOnClickListener {val objectAnimation =ObjectAnimator.ofFloat(llAddAccount, "translationX", 0f, -70f)objectAnimation.start()}
到这里,我们才真正看到属性动画的影子。通过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文件,内容如下:
在代码上调用:
llAddAccount.setOnClickListener {val objectAnimation =AnimatorInflater.loadAnimator(this,R.animator.animator_translation)objectAnimation.setTarget(llAddAccount)objectAnimation.start()}
- 2、透明属性动画
透明度属性动画比较简单,即控制View的可见度实现视觉差动画效果。这里展示效果是从不透明到透明,再到不透明。
代码如下:
tvText.setOnClickListener {val objectAnimation =ObjectAnimator.ofFloat(tvText, "alpha", 1f,0f,1f)objectAnimation.duration=3000objectAnimation.start()}
ofFloat()方法将属性名换成了透明度alpha,并且可变长参数增加到了3个。给ObjectAnimator对象的duration属性设置了动画展示时间3秒,默认情况下300毫秒。
- 3、缩放属性动画
缩放可以通过控制scaleX和scaleY分别在X轴和Y轴上进行缩放,如下图在X轴中进行两次两倍缩放。
代码如下:
tvText.setOnClickListener {val objectAnimation =ObjectAnimator.ofFloat(tvText, "scaleX", 1f,2f)objectAnimation.duration=3000objectAnimation.repeatCount=2objectAnimation.repeatMode=ValueAnimator.REVERSEobjectAnimation.start()}
ofFloat()方法传入参数属性为scaleX和scaleY时,动态参数表示缩放的倍数。设置ObjectAnimator对象的repeatCount属性来控制动画执行的次数,设置为ValueAnimator.INFINITE表示无限循环播放动画;通过repeatMode属性设置动画重复执行的效果,取值为:ValueAnimator.RESTART和ValueAnimator.REVERSE。
ValueAnimator.RESTART效果:(即每次都重头开始)
ValueAnimator.REVERSE效果:(即和上一次效果反着来)
- 4、旋转属性动画
旋转动画也比较简单,将一个View进行顺时针或逆时针旋转。
代码如下:
tvText.setOnClickListener {val objectAnimation =ObjectAnimator.ofFloat(tvText, "rotation", 0f,180f,0f)objectAnimation.duration=3000objectAnimation.start()}
ofFloat()方法的可变长参数,如果后者的值大于前者,那么顺时针旋转,小于前者,则逆时针旋转。
- 5、AnimatorSet
如果想要一个动画结束后播放另外一个动画,或者同时播放,可以通过AnimatorSet来编排。
val aAnimator=ObjectAnimator.ofInt(1)val bAnimator=ObjectAnimator.ofInt(1)val cAnimator=ObjectAnimator.ofInt(1)val dAnimator=ObjectAnimator.ofInt(1)AnimatorSet().apply {play(aAnimator).before(bAnimator)//a 在b之前播放play(bAnimator).with(cAnimator)//b和c同时播放动画效果play(dAnimator).after(cAnimator)//d 在c播放结束之后播放start()}
或者
AnimatorSet().apply {playSequentially(aAnimator,bAnimator,cAnimator,dAnimator) //顺序播放start()}AnimatorSet().apply {playTogether(animator,bAnimator,cAnimator,dAnimator) //同时播放start()}
另有:
AnimatorSet ().apply {play(aAnimator).after(1000) //1秒后播放a动画start()}
二、设置旋转或是平移中心
只能通过要设置动画的控件来设置,无论是 xml 还是代码实现动画都是这样,示例:
val rotateZ = AnimatorInflater.loadAnimator(this, R.animator.rorate_x)//设置中心tv_property_anim.pivotX = 0ftv_property_anim.pivotY = 0ftv_property_anim.invalidate()rotateZ.setTarget(tv_property_anim)rotateZ.start()
三、实现一个控件多个动画
- 使用 ValueAnimator
使用 ValueAnimator 改变控件的宽高:val valueAnimator = ValueAnimator.ofFloat(0f, 500f)valueAnimator.setTarget(tv_property_anim)valueAnimator.duration = 1000valueAnimator.start()valueAnimator.addUpdateListener {tv_property_anim.translationY = it.animatedValue as Float}
private fun testValueAnimatorAnim() {val width2 = tv_property_anim.layoutParams.widthval width = tv_property_anim.widthLogUtils.e("$width----- $width2")val valueAnimator = ValueAnimator.ofInt(width, width * 2)valueAnimator.duration = 2000valueAnimator.addUpdateListener {//当前值LogUtils.e(it.animatedValue)tv_property_anim.layoutParams.width = it.animatedValue as Int//刷新视图,即重新绘制,从而实现动画效果tv_property_anim.requestLayout()}valueAnimator.start()}
- 使用 ValueAnimator
- ObjectAnimator
val anim = ObjectAnimator.ofFloat(tv_property_anim,"AnimatorUtil.SCALE_X",1f, 0f).setDuration(2000)anim.start()anim.addUpdateListener {val fl = it.animatedValue as Floattv_property_anim.alpha = fltv_property_anim.scaleX = fltv_property_anim.scaleY = fl}
- ObjectAnimator
- PropertyValuesHolder
btn_property_propertyValuesHolder.setOnClickListener {val alpha = PropertyValuesHolder.ofFloat(AnimatorUtil.ALPHA, 1f, 0f, 1f)val scalex = PropertyValuesHolder.ofFloat(AnimatorUtil.SCALE_X, 1f, 0f, 1f)val scaley = PropertyValuesHolder.ofFloat(AnimatorUtil.SCALE_Y, 1f, 0f, 1f)ObjectAnimator.ofPropertyValuesHolder(tv_property_anim,alpha,scalex,scaley).setDuration(2000).start()}
- PropertyValuesHolder
- 使用 animtorset
val set = AnimatorSet()val rotation = ObjectAnimator.ofFloat(tv_property_anim,AnimatorUtil.ROTATION,0f,90f)val rotationX = ObjectAnimator.ofFloat(tv_property_anim,AnimatorUtil.ROTATION_X,0f,40f)set.play(rotation).with(rotationX)set.duration = 2000set.start()
四、参考
Android属性动画,看完这篇够用了吧
Android中的View动画和属性动画
Android 属性动画:这是一篇全面 & 详细的 属性动画 总结&攻略
Android 属性动画(Property Animation) 完全解析
Android属性动画完全解析
- 使用 animtorset
