android动画(3)属性动画

1.官方文档

  https://developer.android.com/guide/topics/graphics/prop-animation

  属性动画系统是一个框架,用于为几乎任何对象添加动画效果,无论其是否绘制到屏幕上。属性动画会在指定时长内更改对象某个属性的值。要添加动画效果,请指定要添加动画效果的对象属性,例如对象在屏幕上的位置、动画效果持续多长时间以及要在哪些值之间添加动画效果。

2.属性动画与视图动画的区别

  • 视图动画系统仅为 View 对象添加动画效果的功能
  • 视图动画系统的只会在绘制视图的位置进行修改,而不会修改实际的视图本身。例如,如果为某个按钮添加了动画效果,使其可以在屏幕上移动,该按钮会正确绘制,但能够点击按钮的实际位置并不会更改,因此必须通过实现自己的逻辑来处理此事件。

3.属性动画系统中的主要类

  • TimeInterpolator : 动画插值器,指定运动方式(如保持匀速、先加速后减速等)。
  • TypeEvaluator  :属性的类型及如何计算正在动画中属性的值
  • duration :时长,默认时长为 300 毫秒
  • startProperty :属性的起始值
  • endProperty :属性的结束值
  • start():开始执行动画

3.1 ValueAnimator

  主计时引擎,它具有计算动画值所需的所有核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、用于接收更新事件的监听器以及设置待评估自定义类型的功能。

3.2 ObjectAnimator

  ValueAnimator 的子类,用于设置目标对象和属性。此类会在计算出动画的新值后相应地更新属性。在大多数情况下,使用 ObjectAnimator就可以完成工作

  注意事项

  • 对象属性必须具有 set<PropertyName>() 形式的 setter 函数。
  • 对象属性必须具有 get<PropertyName>() 形式的 getter 函数
  • 属性名字以setter、getter为准,如对象实际属性名为mTextColor,而对应的setter为setTextColor,则要用textColor,而不是用mTextColor
  • getter、setter参数类型与ofXX 类型匹配
  • 如果ofXXX系列方法中仅为 values... 参数指定了一个值,则系统会假定它是动画的结束值。

3.3 AnimatorSet

  复合属性动画。把多个animator组合到一起。如下:

 1     val bouncer = AnimatorSet().apply {
 2         play(bounceAnim).before(squashAnim1)
 3         play(squashAnim1).with(squashAnim2)
 4         play(squashAnim1).with(stretchAnim1)
 5         play(squashAnim1).with(stretchAnim2)
 6         play(bounceBackAnim).after(stretchAnim2)
 7     }
 8     val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
 9         duration = 250
10     }
11     AnimatorSet().apply {
12         play(bouncer).before(fadeAnim)
13         start()
14     }

3.4 求值器

IntEvaluator int求值器
FloatEvaluator float求值器
ArgbEvaluator 颜色属性(用十六进制值表示)求值器
自定义 TypeEvaluator 参阅使用 TypeEvaluator 部分。

3.5 时间插值器

AccelerateDecelerateInterpolator 该插值器的变化率在开始和结束时缓慢但在中间会加快。
AccelerateInterpolator 该插值器的变化率在开始时较为缓慢,然后会加快。
AnticipateInterpolator 该插值器先反向变化,然后再急速正向变化。
AnticipateOvershootInterpolator 该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值。
BounceInterpolator 该插值器的变化会跳过结尾处。
CycleInterpolator 该插值器的动画会在指定数量的周期内重复。
DecelerateInterpolator 该插值器的变化率开始很快,然后减速。
LinearInterpolator 该插值器的变化率恒定不变。
OvershootInterpolator 该插值器会急速正向变化,再超出最终值,然后返回。
TimeInterpolator 用于自定义插值器

该接口用于实现您自己的插值器。

https://developer.android.com/guide/topics/graphics/prop-animation#interpolators

3.6 Animator的回调接口

  • ValueAnimator.AnimatorUpdateListener 属性更新接口
  • Animator.AnimatorListener 属性动画的完整接口,包括(开始、结束、取消、重复)
  • Animator.AnimatorPauseListener 动画暂停、重新开始
  • AnimatorListenerAdapter 一个抽象类(动画开始、结束)

3.7 KeyFrame

  用来指定动画中的某一帧为关键帧,并自定义其中的行为或状态等。

 1     private fun onKeyFrameClicked(v : View){
 2         val kf0 = Keyframe.ofFloat(0f, 0f)      //第1帧
 3         val kf1 = Keyframe.ofFloat(0.5f, 360f)  //中间帧
 4         val kf2 = Keyframe.ofFloat(1f, 0f)      //最后1帧
 5         val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
 6         ObjectAnimator.ofPropertyValuesHolder(binding.animatorTitle, pvhRotation).apply {
 7             duration = 5000
 8 //            interpolator = OvershootInterpolator()
 9 //            interpolator = CycleInterpolator(0.5f)
10             interpolator = AccelerateDecelerateInterpolator()
11             start()
12         }
13     }

4.View 对象使用属性动画

  View类也可以使用属性动画,通过animate()方法返回一个ViewPropertyAnimator 对象,它就是view使用属性动画的简化类,直接使用相应的动画方法就可以了。

  详见:https://developer.android.com/reference/android/view/ViewPropertyAnimator

 4.2 示例

1     private fun onViewAnimate(v : View){
2         val x = textView.translationX
3         textView.animate().translationX(x + 20f)
4     }

   使用了translationX动画。

4.2 View基类已经支持的属性 

translationX 和 translationY 控制视图所在的位置,值为视图的布局容器所设置的左侧坐标和顶部坐标的
rotation、rotationX 和 rotationY 控制视图围绕轴心点进行的 2D( 属性)和 3D 旋转。
scaleX 和 scaleY 控制视图围绕其轴心点进行的 2D 缩放。
pivotX 和 pivotY 控制旋转和缩放转换所围绕的轴心点的位置。默认情况下,轴心点位于对象的中心
x 和 y 描述视图在容器中的最终位置,值分别为左侧值与 translationX 值的和以及顶部值与 translationY 值的和。
alpha 表示视图的 Alpha 透明度。此值默认为 1(不透明),值为 0 则表示完全透明(不可见)

  view的子类 参见其中的setter与getter,如TextView的textColor属性

5.代码中直接使用属性动画

5.1 ValueAnimator和相关listener

 1      val animatorUpdate = object : ValueAnimator.AnimatorUpdateListener {
 2             override fun onAnimationUpdate(animation: ValueAnimator?) {
 3                 val value = animation?.animatedValue
 4                 Log.e("MainActivity","AnimatorUpdateListener value = $value")
 5             }
 6         }
 7         val animatorListener = object : Animator.AnimatorListener{
 8             override fun onAnimationStart(animation: Animator?) {
 9                 Log.e("MainActivity","AnimatorListener onAnimationStart")
10             }
11 
12             override fun onAnimationEnd(animation: Animator?) {
13                 Log.e("MainActivity","AnimatorListener onAnimationEnd")
14             }
15 
16             override fun onAnimationCancel(animation: Animator?) {
17                 Log.e("MainActivity","AnimatorListener onAnimationCancel")
18             }
19 
20             override fun onAnimationRepeat(animation: Animator?) {
21                 Log.e("MainActivity","AnimatorListener onAnimationRepeat")
22             }
23         }
24         val animatorAdapter = object : AnimatorListenerAdapter(){
25             override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
26                 super.onAnimationStart(animation, isReverse)
27                 Log.e("MainActivity","AnimatorListenerAdapter onAnimationStart")
28             }
29 
30             override fun onAnimationEnd(animation: Animator?, isReverse: Boolean) {
31                 super.onAnimationEnd(animation, isReverse)
32                 Log.e("MainActivity","AnimatorListenerAdapter onAnimationEnd")
33             }
34         }
35         ValueAnimator.ofFloat(0f, 100f).apply {
36             addUpdateListener(animatorUpdate)
37             addListener(animatorAdapter)
38             interpolator = DecelerateInterpolator()
39             duration = 1000
40             start()
41         }

5.2 ObjectAnimator

1        val translation = ObjectAnimator.ofFloat(binding.animatorTitle, "translationX", end).apply {
2             duration = 1000
3             interpolator = AnticipateInterpolator()
4             start()
5         }

5.3 AnimatorSet

  可顺序播放,也可以自定义播放顺序。

 1         //动画1
 2         val end = if(binding.animatorTitle.translationX < binding.root.measuredWidth / 2) binding.root.measuredWidth / 2f else 0f
 3         val translation = ObjectAnimator.ofFloat(binding.animatorTitle, "translationX", end).apply {
 4             duration = 1000
 5             interpolator = AccelerateInterpolator()
 6         }
 7         //动画2
 8         val fade1 = ObjectAnimator.ofFloat(binding.animatorTitle, "alpha", 1f, 0.5f).apply {
 9             duration = 1000
10         }
11         //动画3
12         val fade2 = ObjectAnimator.ofFloat(binding.animatorTitle, "alpha", 0.5f, 1f).apply {
13             duration = 1000
14         }
15 
16         AnimatorSet().apply {
17             /*
18             play(fade1)                         //顺序播放
19             play(fade2)
20             play(translation)
21             */
22             play(fade1).before(fade2)           //之前播放
23             play(translation).after(fade2)      //在之后播放
24             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
25                 val startColor = Color.parseColor("#000000")
26                 val endColor = Color.parseColor("#ff0000")
27                 val color = ObjectAnimator.ofArgb(binding.animatorTitle, "textColor", startColor,endColor).apply {
28                     duration = 1000
29                     interpolator = AccelerateDecelerateInterpolator()
30                 }
31                 play(translation).with(color)   //同时播放
32             }
33             start()
34         }

5.4 Keyframe

 1     private fun onKeyFrameClicked(v : View){
 2         val kf0 = Keyframe.ofFloat(0f, 0f)      //第1帧
 3         val kf1 = Keyframe.ofFloat(0.5f, 360f)  //中间帧
 4         val kf2 = Keyframe.ofFloat(1f, 0f)      //最后1帧
 5         val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
 6         ObjectAnimator.ofPropertyValuesHolder(binding.animatorTitle, pvhRotation).apply {
 7             duration = 5000
 8 //            interpolator = OvershootInterpolator()
 9 //            interpolator = CycleInterpolator(0.5f)
10             interpolator = AccelerateDecelerateInterpolator()
11             start()
12         }
13     }

6. 在资源文件中定义属性动画

ValueAnimator <animator>
ObjectAnimator <objectAnimator>
AnimatorSet <set>

6.1 animated-selector

  animated-selector 要放在 v21 及更高的目录下,如:animator_btn_state.xml 

 1 <animated-selector
 2     xmlns:android="http://schemas.android.com/apk/res/android">
 3 
 4     <!-- provide a different drawable for each state-->
 5     <item android:id="@+id/pressed" android:drawable="@drawable/animator_btn_pressed"
 6         android:state_pressed="true"/>
 7     <item android:id="@+id/release" android:drawable="@drawable/animator_btn_normal"
 8         android:state_pressed="false"/>
 9     <item android:id="@+id/normal"
10         android:drawable="@drawable/btn_normal"/>
11 
12     <!-- specify a transition -->
13     <transition android:fromId="@+id/pressed" android:toId="@+id/release">
14         <animation-list>
15             <item android:duration="15" android:drawable="@drawable/animator_btn_pressed"/>
16             <item android:duration="15" android:drawable="@drawable/animator_btn_normal"/>
17         </animation-list>
18     </transition>
19 </animated-selector>

  其中 id是自定义的。

  button使用它

1     <Button
2         ...
3         android:stateListAnimator="@animator/animator_scale_state"
4         ... />

6.2 animator (translationX)

1 <?xml version="1.0" encoding="utf-8"?>
2 <animator xmlns:android="http://schemas.android.com/apk/res/android"
3     android:interpolator="@android:anim/linear_interpolator"
4     android:repeatCount="0"
5     android:repeatMode="restart"
6     android:duration="1000"
7     android:valueType="floatType"
8     android:valueTo="100f" />

  解析后是  ValueAnimator 对象,代码中使用它:

 1     private fun onXmlTranslation1AnimatorClicked(v : View){
 2         val update = object : ValueAnimator.AnimatorUpdateListener {
 3             override fun onAnimationUpdate(animation: ValueAnimator?) {
 4                 val value = animation?.animatedValue as Float
 5                 Log.e("MainActivity","AnimatorUpdateListener value = $value")
 6                 binding.animatorTitle.translationX = value
 7             }
 8         }
 9         (AnimatorInflater.loadAnimator(baseContext, R.animator.animator_translation1) as ValueAnimator).apply {
10             setTarget(binding.animatorView)
11             addUpdateListener(update)
12             start()
13         }
14     }

  在资源中定义的ValueAnimator属性动画,需要updateListener且在更新回调中刷新view

6.3 objectAnimator (translationY)

1 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
2     android:duration="1000"
3     android:propertyName="translationY"
4     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
5     android:valueFrom="0"
6     android:valueTo="50f" />

  解析后是 ObjectAnimator 对象,代码中使用它:

1     private fun onXmlTranslation2AnimatorClicked(v : View){
2         (AnimatorInflater.loadAnimator(baseContext, R.animator.animator_translation2) as ValueAnimator).apply {
3             setTarget(binding.animatorView)
4             start()
5         }
6     }

6.4 AnimatorSet

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <set android:ordering="sequentially"
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4     <!--ordering 可选值 : together(默认) 同时播放 ,sequentially 顺序播放-->
 5     <set>
 6         <objectAnimator
 7             android:propertyName="x"
 8             android:duration="500"
 9             android:valueTo="100"
10             android:valueFrom="0"
11             android:valueType="intType"/>
12         <objectAnimator
13             android:propertyName="y"
14             android:duration="500"
15             android:valueTo="100"
16             android:valueFrom="0"
17             android:valueType="intType"/>
18     </set>
19     <objectAnimator
20         android:propertyName="alpha"
21         android:duration="1000"
22         android:valueType="floatType"
23         android:valueFrom="0.1f"
24         android:valueTo="1f"
25         />
26 </set>

  解析后是AnimatorSet对象,在代码中使用示例如下:

1     private fun onXmlSetAnimatorClicked(v : View){
2         (AnimatorInflater.loadAnimator(baseContext, R.animator.animator_set) as AnimatorSet).apply {
3             setTarget(binding.animatorTitle)
4             start()
5         }
6 
7     }

6.5 alpha、rotation、scale

  • alpha
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:interpolator="@android:anim/linear_interpolator"
 4     android:propertyName="alpha"
 5     android:repeatCount="0"
 6     android:repeatMode="restart"
 7     android:duration="3000"
 8     android:valueType="floatType"
 9     android:valueFrom="0.1f"
10     android:valueTo="1f" />
  • rotation
1 <?xml version="1.0" encoding="utf-8"?>
2 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
3     android:propertyName="rotation"
4     android:repeatCount="0"
5     android:repeatMode="restart"
6     android:duration="6000"
7     android:valueFrom="0"
8     android:valueTo="360" />
  • scale
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
 4     android:propertyName="scaleY"
 5     android:duration="5000"
 6     android:valueTo="3f"
 7     android:valueFrom="1"
 8     android:repeatCount="-1"
 9     android:repeatMode="restart"
10     />

 

   代码中使用方法与6.3中类似。

 

posted @ 2015-05-06 16:39  f9q  阅读(441)  评论(0编辑  收藏  举报