💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
#### 7.3.1 使用属性动画 属性动画可以对任意对象的属性进行动画而不仅仅是View,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对象从一个属性值到另一个属性值的改变。因此,属性动画几乎是无所不能的,只要对象有这个属性,它都能实现动画效果。但是属性动画从API 11才有,这就严重制约了属性动画的使用。可以采用开源动画库nineoldandroids来兼容以前的版本,采用nineoldandroids,可以在API 11以前的系统上使用属性动画,nineoldandroids的网址是:http://nineoldandroids.com。 Nineoldandroids对属性动画做了兼容,在API 11以前的版本其内部是通过代理View动画来实现的,因此在Android低版本上,它的本质还是View动画,尽管使用方法看起来是属性动画。Nineoldandroids的功能和系统原生对的android.animation.*中类的功能完全一致,使用方法也完全一样,只要我们用nineoldandroids来编写动画,就可以在所有的Android系统上运行。比较常用的几个动画类是:ValueAnimator、ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自ValueAnimator, AnimatorSet是动画集合,可以定义一组动画,它们使用起来也是极其简单的。如何使用属性动画呢?下面简单举几个小例子,读者一看就明白了。 (1)改变一个对象(myObject)的translationY属性,让其沿着Y轴向上平移一段距离:它的高度,该动画在默认时间内完成,动画的完成时间是可以定义的。想要更灵活的效果我们还可以定义插值器和估值算法,但是一般来说我们不需要自定义,系统已经预置了一些,能够满足常用的动画。 ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()). start(); (2)改变一个对象的背景色属性,典型的情形是改变View的背景色,下面的动画可以让背景色在3秒内实现从0xFFFF8080到0xFF8080FF的渐变,动画会无限循环而且会有反转的效果。 ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF); colorAnim.setDuration(3000); colorAnim.setEvaluator(new ArgbEvaluator()); colorAnim.setRepeatCount(ValueAnimator.INFINITE); colorAnim.setRepeatMode(ValueAnimator.REVERSE); colorAnim.start(); (3)动画集合,5秒内对View的旋转、平移、缩放和透明度都进行了改变。 AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(myView, "rotationX", 0, 360), ObjectAnimator.ofFloat(myView, "rotationY", 0, 180), ObjectAnimator.ofFloat(myView, "rotation", 0, -90), ObjectAnimator.ofFloat(myView, "translationX", 0, 90), ObjectAnimator.ofFloat(myView, "translationY", 0, 90), ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f), ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f), ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1) ); set.setDuration(5 * 1000).start(); 属性动画除了通过代码实现以外,还可以通过XML来定义。属性动画需要定义在res/animator/目录下,它的语法如下所示。 <set android:ordering=["together" | "sequentially"]> <objectAnimator android:propertyName="string" android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/> <animator android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/> <set> ... </set> </set> 属性动画的各种参数都比较好理解,在XML中可以定义ValueAnimator、Object-Animator以及AnimatorSet,其中<set>标签对应AnimatorSet, <animator>标签对应ValueAnimator,而<objectAnimator>则对应ObjectAnimator。<set>标签的android:ordering属性有两个可选值:“together”和“sequentially”,其中“together”表示动画集合中的子动画同时播放,“sequentially”则表示动画集合中的子动画按照前后顺序依次播放,android:ordering属性的默认值是“together”。 对于<objectAnimator>标签的各个属性的含义,下面简单说明一下,对于<animator>标签这里就不再介绍了,因为它只是比<objectAnimator>少了一个android:propertyName属性而已,其他都是一样的。 · android:propertyName——表示属性动画的作用对象的属性的名称; · android:duration——表示动画的时长; · android:valueFrom——表示属性的起始值; · android:valueTo——表示属性的结束值; · android:startOffset——表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才会真正播放此动画; · android:repeatCount——表示动画的重复次数; · android:repeatMode——表示动画的重复模式; · android:valueType——表示android:propertyName所指定的属性的类型,有“intType”和“floatType”两个可选项,分别表示属性的类型为整型和浮点型。另外,如果android:propertyName所指定的属性表示的是颜色,那么不需要指定android:valueType,系统会自动对颜色类型的属性做处理。 对于一个动画来说,有两个属性这里要特殊说明一下,一个是android:repeatCount,它表示动画循环的次数,默认值为0,其中-1表示无限循环;另一个是android:repeatMode,它表示动画循环的模式,有两个选项:“repeat”和“reverse”,分别表示连续重复和逆向重复。连续重复比较好理解,就是动画每次都重新开始播放,而逆向重复是指第一次播放完以后,第二次会倒着播放动画,第三次再重头开始播放动画,第四次再倒着播放动画,如此反复。 下面是一个具体的例子,我们通过XML定义一个属性动画并将其作用在View上,如下所示。 // res/animator/property_animator.xml <set android:ordering="together"> <objectAnimator android:propertyName="x" android:duration="300" android:valueTo="200" android:valueType="intType"/> <objectAnimator android:propertyName="y" android:duration="300" android:valueTo="300" android:valueType="intType"/> </set> 如何使用上面的属性动画呢?也很简单,如下所示。 AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator); set.setTarget(mButton); set.start(); 在实际开发中建议采用代码来实现属性动画,这是因为通过代码来实现比较简单。更重要的是,很多时候一个属性的起始值是无法提前确定的,比如让一个Button从屏幕左边移动到屏幕的右边,由于我们无法提前知道屏幕的宽度,因此无法将属性动画定义在XML中,在这种情况下就必须通过代码来动态地创建属性动画。