让View跟随状态动起来——StateListAnimator
StateListAnimator定义了一组动画,可以根据View drawable的状态进行不同的切换。所谓状态指的是state_pressed、state_enabled等这些状态。
Android提供的drawable中,其中有一种就是selector,只不过那种是指定的图片,而StateListAnimator指定的动画。
不说废话,先看下效果:
使用StateListAnimator
StateListAnimator主要就是定义不同状态下的动画,主要有三种方式可以实现:
- 完全xml定义动画以及设置
- xml定义动画+代码设置
- 代码定义动画以及设置
下面分别介绍。
xml定义动画以及设置
在res/animator下创建动画文件,根标签selector,然后定义每种状态下的动画,demo中左上角的动画就是这么定义的,如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<set>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:repeatCount="10"
android:repeatMode="restart"
android:valueFrom="1.0"
android:valueTo="1.5"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleY"
android:repeatCount="10"
android:repeatMode="restart"
android:valueFrom="1.0"
android:valueTo="1.5"
android:valueType="floatType"/>
</set>
</item>
<!-- the default, non-pressed state; set x and y size to 100% -->
<item android:state_pressed="false">
<set>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleY"
android:valueTo="1"
android:valueType="floatType"/>
</set>
</item>
</selector>
主要定义了在按住状态下的缩放动画,重复10次;正常状态下恢复到正常状态。定义好了动画后,只需在xml中使用stateListAnimator进行设置,如下:
<ImageView
android:clickable="true"
android:src="@drawable/pic_11"
android:stateListAnimator="@animator/anim_list_state_scale"
/>
需要注意的是,使用了state_pressed状态后,如果这个View默认是不支持点击的,比如自定义View、ImageView等,那么还需要添加clickable=true,不然是没有效果的,切记切记。
xml定义动画+代码设置
demo中右上的动画,就是这种方式,xml定义动画和上面一样,就不多bb了,代码设置如下:
cardView.stateListAnimator=AnimatorInflater.loadStateListAnimator(this,R.animator.card_smooth_shadow)
代码定义动画以及设置
demo中心动的感觉就是通过这种方式设置的,纯代码定义动画。动画效果也是在按下去的时候进行一个无限循环的缩放,正常状态下恢复到正常状态。
代码如下:
val xPressedAnim = ObjectAnimator.ofFloat(ivLike, View.SCALE_X, 1.0f, 1.5f).apply {
duration = 1000
repeatMode = ValueAnimator.REVERSE
repeatCount = ValueAnimator.INFINITE
}
val yPressedAnim = ObjectAnimator.ofFloat(ivLike, View.SCALE_Y, 1.0f, 1.5f).apply {
duration = 1000
repeatMode = ValueAnimator.REVERSE
repeatCount = ValueAnimator.INFINITE
}
val xNormalAnim = ObjectAnimator.ofFloat(ivLike, View.SCALE_X, 1.0f).apply {
duration = 1000
}
val yNormalAnim = ObjectAnimator.ofFloat(ivLike, View.SCALE_Y, 1.0f).apply {
duration = 1000
}
val pressedAnim = AnimatorSet().apply {
play(xPressedAnim).with(yPressedAnim)
}
val normalAnim = AnimatorSet().apply {
play(xNormalAnim).with(yNormalAnim)
}
//这个不能少,否则没有效果
ivLike.isClickable=true
ivLike.stateListAnimator = StateListAnimator().apply {
addState(intArrayOf(android.R.attr.state_pressed), pressedAnim)
//负数表示该状态为false
addState(intArrayOf(-android.R.attr.state_pressed), normalAnim)
}
代码其实挺简单的,StateListAnimator定义后,通过addState()指定某些方法下的动画,状态都是在android.R.attr.state_XXX下,每种状态有true或者false,如果需要加上false,需要在值前面加上负号就可以了,如上面的代码。
总结
StateListAnimator的创建主要有三种方式,而根本还是属性动画的定义,因此属性动画才是关键。
参考
- https://developer.android.com/guide/topics/graphics/prop-animation?hl=zh-cn#ViewState
- https://developer.android.com/reference/android/animation/StateListAnimator?hl=zh-cn
- https://android.jlelse.eu/polishing-ui-android-statelistanimator-7b74a06b85a5
- https://blog.stylingandroid.com/statelistanimator/
- https://blog.stylingandroid.com/animatedstatelistdrawable/
关注我的技术公众号,不定期会有技术文章推送,不敢说优质,但至少是我自己的学习心得。微信扫一扫下方二维码即可关注:
二维码