Android 动画之属性动画(四)#
Specifying Keyframes##
有些时候,我们需要这个动画在进程的某一个时刻,达到某一个指定的值。比如说你实现一个位移动画,然后你想在进程的1/2,位移走到3/4,当然你可以重写 TimeInterpolator 达到这样的效果,但是如果情况更加复杂,那么难以保证你可以写出正确的逻辑来满足要求,于是就有了 Keyframes
Keyframe ,就是关键帧,也就是 flash 里面的关键帧。flash 里面的关键帧就是,在指定位置,你放一张帧,然后系统就会自动为两个关键帧计算出补间动画。紧连着的两个帧之间,之间的动画的 Interpolator 也是可以分别指定的
Keyframe 的使用方法:
- 首先获得一个Keyframe对象,对象的获得一般是通过调用 ofInt(), ofFloat(), or ofObject() 来获得。ofFloat( float fraction, float value ) 具体来看参数,第一个参数为 fraction ,也就是之前讲到的代表进程的参数,第二个就是 value 就是 Interpolator 返回的值。这个方法意思就是这一帧在进程为 fraction 的时候,对应的值为 value。
- 利用 PropertyValuesHolder.ofKeyframe( String propertyName, Keyframe... values ) ,把 Keyframe封装到 PropertyValuesHolder 里面
- 调用 ObjectAnimator.ofPropertyValuesHolder( Object target, PropertyValuesHolder... pvhRotation ) 方法为 ObjectAnimator 设置动画
具体代码:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
//这样,可以把动画看做看做有三个关键帧,分别是在进程为0的时候value为0,在进程为1/2的时候值为360...
大家可以看到,ObjectAnimator.ofPropertyValuesHolder( Object target, PropertyValuesHolder... pvhRotation ) 的第二个参数是不定的,也就是说,我们可以传入若干个 PropertyValuesHolder ,也就是说我们可以实现两个动画效果同时发生。按照以前所讲的,要两个动画同时进行的方法是:
ObjectAnimator ob1 = ObjectAnimator.ofFloat(myView,"rotation",0f,125f,0,-125f,0f);
ObjectAnimator ob2 = ObjectAnimator.ofFloat(myView,"textSize",25f,50f,25f,50f,25f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(ob1).with(ob2);
animatorSet.setDuration(5000);
animatorSet.start();
这样就实现了一个文本框文字放大和旋转同时进行的动画效果,但是这里用到了 AnimatorSet 以及创建了两个 ObjectAnimator 类对象,那么我们来看用 PropertyValuesHolder 来实现
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
PropertyValuesHolder pvhRTextSize = PropertyValuesHolder.ofKeyframe("textSize", kf3, kf4, kf5);
ObjectAnimator rotationAndSizeAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation,pvhTextSize)
rotationAnim.setDuration(5000ms);
这样就只需要一个 ObjectAnimator 类对象就好了
更多关于 PropertyValuesHolder 请查看官方文档
https://developer.android.com/reference/android/animation/PropertyValuesHolder.html
更多关于 Keyframe 请查看官方文档
https://developer.android.com/reference/android/animation/Keyframe.html#setValue(java.lang.Object)
Animating Views##
在第一篇的时候有跟大家说过 补间动画 只能改变 view 的图形,而实际并没有动。这是因为在以前额的API版本里面,动画的效果的实现是通过改变它们图像界面的绘制来实现的,并没有真正地改变 view 的属性。在 Android 3.0后,view 增加了很多的属性以及增加了对应的 getter 和 setter 方法,于是也就有了 属性动画 ,从而消除上述的弊端。
新增加的属性:
- translationX and translationY: 这两个参数控制 view 在容器中的位置,一个控制 x 轴方向,一个控制 y 轴方向。它们两个是一个差值,大小定义为 view 的实际坐标 x,y 减去在开始在容器里面设置的 x0,y0,也就是 translationX/Y = x/y -x0/y0
- rotation, rotationX, and rotationY: 这些参数控制 view 在2D平面和在3D平面上的旋转,并且是围绕中心点旋转的
- scaleX and scaleY: 这些参数控制 view 围绕中心点进行2D平面上的缩放
- pivotX and pivotY: 这些参数控制 view 的中心点,默认为 view 图像的中心点,也是rotation 动画和 scale 动画进行时的中心点
- x and y: view 在容器中的实际坐标
- alpha: 代表控件的透明度,范围1~0,默认为1,0表示完全透明
Animating with ViewPropertyAnimator##
ViewPropertyAnimator 顾名思义,是专门用于 view 的动画类。回顾一下之前讲得内容,可以看到,我们要实现一个 view 的动画效果,都是要新建一个 Animator 类,然后再把目标 view 当做参数传到它里面,这样其实是很不符合认得思维习惯。我们正常的思维习惯是,有一个 view ,然后我们可以通过 view 的子方法调用来时动画。比如想要一个 view 实现 x 方向的移动,那么就可以是
view.x(50);
实际上,Android官方就提供 ViewPropertyAnimator 类来满足上述的要求。它比起直接新建一个 Animator 类的有事在于
- 它可以直接用 view 通过调用特定的方法,比如 .x(50) 就可以实现动画效果,尽管底层仍是调用 Animator 来实现动画效果,但是我们不需要理会系统是怎样实现的,保证了代码的简洁和易读性
- 在对 view 执行多个动画的时候,如果是用 Animator 类来实现的话,每一个属性的改变都会去调用 invalidate() 方法,这样系统处理起来就不够好,降低性能。但是使用 ViewPropertyAnimator ,它会自动计算出调用 invalidate() 的最优时间,提高性能。
下面我们来对比一下几种对一个 view 实现多个动画的方法
Multiple ObjectAnimator objects
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
One ObjectAnimator
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator
myView.animate().x(50f).y(100f);
更多关于 ViewPropertyAnimator 请查看官方文档
https://developer.android.com/reference/android/view/ViewPropertyAnimator.html
Declaring Animations in XML##
属性动画 允许我们用 XML 文件的形式创建动画。通过 XML 文件创建动画,我们就可以在多个Activity 里面重用这些动画。并且对动画进行修改,只需要修改 XML 文件就可以修改所有的使用这个 XML 文件的动画。
这个 XML 文件必须放在 res/animator/ 目录下,也就意味着你要在 res 里面新建一个 animator 文件夹,然后在里面新建你的 XML 文件
定义动画 XML 的标签有如下三个:
- ValueAnimator - < animator >
- ObjectAnimator - < objectAnimator >
- AnimatorSet - < set >
使用 XML 动画的步骤:
- 在 res/animator/ 目录下创建一个 XML 文件,并编写代码。在这个目录下,这个 XML 文件会自动在 R文件里的 animator 类中生成一个 id 来表示它,这里我们命名 XML 为 property_animator ,则它的 id 就为 R.id.property_animator
- 然后就需要在代码中调用它,方法是在代码中定义一个 AnimatorSet 类,然后通过 AnimatorInflater 类的 loadAnimator( Context context , int id ) 来解析 XML 里定义的动画,并传到 AnimatorSet 对象中
- 最后为这个 AnimatorSet 对象通过 setTarget( Object Target ) 来设置需要进行该动画的目标
例子:
property_animator.xml
code
AnimatorSet animatorSet =(AnimatorSet) AnimatorInflater.loadAnima(this,
R.animator.property_anim);
animatorSet.setTarget(button);
animatorSet.start();
至此,关与属性动画所有的知识已经结束,在下面给出的链接是官方关于属性动画的API demo
https://android.googlesource.com/platform/development/+/654f51a/samples/ApiDemos/src/com/example/android/apis/animation?autodive=0%2F/