关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。
我们继续总结学习基础知识,温故知新。
属性动画系统是一个强健的框架,用于为几乎任何内容添加动画效果。您可以定义一个随时间更改任何对象属性的动画,无论其是否绘制到屏幕上。
属性动画会在指定时长内更改属性(对象中的字段)的值。要添加动画效果,请指定要添加动画效果的对象属性,
例如对象在屏幕上的位置、动画效果持续多长时间以及要在哪些值之间添加动画效果。
借助属性动画系统,您可以定义动画的以下特性:
属性动画的主计时引擎,它也可计算要添加动画效果的属性的值。它具有计算动画值所需的所有核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、
用于接收更新事件的监听器以及设置待评估自定义类型的功能。为属性添加动画效果分为两个步骤:计算添加动画效果之后的值,以及对要添加动画效果的对象和属性设置
这些值。
ValueAnimator 不会重复,因此,您必须监听由 ValueAnimator 计算的值的更新情况,并使用您自己的逻辑修改要添加动画效果的对象。
这是 ValueAnimator 的子类,用于设置目标对象和对象属性以添加动画效果。
此类会在计算出动画的新值后相应地更新属性。在大多数情况下,您不妨使用 ObjectAnimator,因为它可以极大地简化对目标对象的值添加动画效果这一过程。不过,有时您需要直接使用 ValueAnimator,
因为 ObjectAnimator 存在其他一些限制,例如要求目标对象具有特定的访问器方法。
此类提供一种将动画分组在一起的机制,以使它们彼此相对运行。您可以将动画设置为一起播放、按顺序播放或者在指定的延迟时间后播放。
时间插值器指定了如何根据时间计算动画中的特定值。例如,您可以指定动画在整个动画中以线性方式播放,即动画在整个播放期间匀速移动;也可以指定动画使用非线性时间,
例如动画在开始后加速并在结束前减速。 下面表格 介绍了 android.view.animation 中包含的插值器。
如果下表提供的插值器都不能满足您的需求,请实现 TimeInterpolator 接口并创建您自己的插值器。
类/接口 | 说明 |
---|---|
AccelerateDecelerateInterpolator | 该插值器的变化率在开始和结束时缓慢但在中间会加快。 |
AccelerateInterpolator | 该插值器的变化率在开始时较为缓慢,然后会加快。 |
AnticipateInterpolator | 该插值器先反向变化,然后再急速正向变化。 |
AnticipateOvershootInterpolator | 该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值。 |
BounceInterpolator | 该插值器的变化会跳过结尾处。 |
CycleInterpolator | 该插值器的动画会在指定数量的周期内重复。 |
DecelerateInterpolator | 该插值器的变化率开始很快,然后减速。 |
LinearInterpolator | 该插值器的变化率恒定不变。 |
OvershootInterpolator | 该插值器会急速正向变化,再超出最终值,然后返回。 |
TimeInterpolator | 该接口用于实现您自己的插值器。 |
可以在xml中定义,也可直接在代码中使用
语法如下:
指定此集合中动画的播放顺序, sequentially 依序播放此集合中的动画。 together(默认) 同时播放此集合中的动画。
如果值为颜色,则不要指定此属性。动画框架会自动处理颜色值。 intType 指定动画值为整数。 floatType(默认) 指定动画值为浮点数。
<set>
...
set>
set>
其实也可以不用 set包裹,定义单一的动画
我们举例:
定义xml动画,然后在代码中调用开始动画。
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
set>
开始动画
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animator.property_animator);
set.setTarget(myObject); // 必须操作
set.start();
借助 ValueAnimator 类,您可以为动画播放期间某些类型的值添加动画效果,只需指定一组要添加动画效果的 int、float 或颜色值即可。
您可以通过调用 ValueAnimator 的任一工厂方法来获取它:ofInt()、ofFloat() 或 ofObject()。例如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationResume(Animator animation) {
}
@Override
public void onAnimationPause(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// do something
}
});
animator.setRepeatCount(2);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setInterpolator(interpolator);
animation.start();
在上述代码中,当 start() 方法运行时,ValueAnimator 会开始计算 1000ms 时长内 0 和 100 之间的动画的值。
ObjectAnimator 是上一部分中讨论的 ValueAnimator 的子类,它融合了 ValueAnimator 的计时引擎和值计算以及为目标对象的命名属性添加动画效果这一功能。
这可以极大地简化为任何对象添加动画效果的过程,因为动画属性会自动更新,因此您也无需再实现 ValueAnimator.AnimatorUpdateListener 了。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "alpha", 0.3f, 1f);
objectAnimator1.setDuration(1000);
objectAnimator1.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator1.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator1.start();
上面的代码是修改view的透明度,看到构造方法里面的那个 “alpha” 了吧,我们在构造时,传入的对象,如上面的view,
必须包含有setAlpha()方法,否则设置是失败的,我们看view的源码,发现果然有
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha)
还有很多其他的
public void setRotation(float rotation)
public void setRotationX(float rotation)
public void setRotationY(float rotation)
public void setBackgroundColor(@ColorInt int color)
public void setScaleX(float scaleX)
public void setScaleY(float scaleX)
public void setTranslationX(float translationX)
public void setTranslationY(float translationX)
等等
所以可以有
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 0f, xValue, 0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "translationY", 0f, yValue, 0f);
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f, 1f, 0.95f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f, 1f, 0.95f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "rotation", 0.0F, 360f);
等等
这里面的属性可以随意指定,只要我们要做动画的类中包含有该属性的set方法,例如:
public class Test {
public final void setProcess(final float process) {
}
ObjectAnimator mProcessAnimator = ObjectAnimator.ofFloat(this, "process", 0, 0)
}
要使 ObjectAnimator 正确更新属性,您必须执行以下操作:
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
使用AnimatorSet ,可以指定是同时播放动画、按顺序播放还是在指定的延迟时间后播放。还可以相互嵌套 AnimatorSet 对象。
举例:
以下代码段通过以下方式播放相应的 Animator 对象:
1、播放 bounceAnim。
2、同时播放 squashAnim1、squashAnim2、stretchAnim1 和 stretchAnim2。
3、播放 bounceBackAnim。
4、播放 fadeAnim。
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
下面同时播放3个动画
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "alpha", 0.3f, 1f);
objectAnimator1.setDuration(1000);
objectAnimator1.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator1.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "rotation", 0.0F, 360f);
objectAnimator2.setDuration(5000);
objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setInterpolator(new LinearInterpolator());
animatorSet.playTogether(objectAnimator1, objectAnimator2);
animatorSet.start();
您可以使用下述监听器来监听动画播放期间的重要事件。
Animator.AnimatorListener
ValueAnimator.AnimatorUpdateListener
将 ViewGroup 的 android:animateLayoutchanges 属性设置为 true,将此属性设置为 true 可自动为添加到 ViewGroup 或从中删除的视图以及该 ViewGroup 中剩余的视图添加动画效果
eg:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
使用根 元素和子 元素在 XML 资源中定义 StateListAnimator,每个元素都指定一个由 StateListAnimator 类定义的不同视图状态。每个 都包含一个属性动画集的定义。
例如,以下文件创建了一个状态列表 Animator,可在按下后更改视图的 x 和 y 比例:
res/xml/animate_scale.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<set>
<objectAnimator android:propertyName="scaleX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1.5"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1.5"
android:valueType="floatType"/>
set>
item>
<item android:state_pressed="false">
<set>
<objectAnimator android:propertyName="scaleX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1"
android:valueType="floatType"/>
set>
item>
selector>
要将状态列表 Animator 附加到视图,请添加 android:stateListAnimator 属性,如下所示:
<Button android:stateListAnimator="@xml/animate_scale"
... />
现在,当此按钮的状态发生变化时,会使用 animate_scale.xml 中定义的动画。
或者,如果要转为在代码中将状态列表 Animator 分配给视图,则可使用 AnimatorInflater.loadStateListAnimator() 方法,
然后使用 View.setStateListAnimator() 方法将 Animator 分配给相应视图。
您还可以使用 AnimatedStateListDrawable 在状态更改间播放可绘制动画,而不是为视图的属性添加动画效果。
Android 5.0 中的一些系统微件默认会使用这些动画。以下示例展示了如何将 AnimatedStateListDrawable 定义为 XML 资源:
<animated-selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
android:state_pressed="true"/>
<item android:id="@+id/focused" android:drawable="@drawable/drawableF"
android:state_focused="true"/>
<item android:id="@id/default"
android:drawable="@drawable/drawableD"/>
<transition android:fromId="@+id/default" android:toId="@+id/pressed">
<animation-list>
<item android:duration="15" android:drawable="@drawable/dt1"/>
<item android:duration="15" android:drawable="@drawable/dt2"/>
...
animation-list>
transition>
...
animated-selector>
如果要为 Android 系统无法识别的类型添加动画效果,则可以通过实现 TypeEvaluator 接口来创建您自己的评估程序。
Android 系统可以识别的类型为 int、float 或颜色,分别由 IntEvaluator、FloatEvaluator 和 ArgbEvaluator 类型评估程序提供支持。
TypeEvaluator 接口中只有一种要实现的方法,那就是 evaluate() 方法。这样,您使用的 Animator 就会在动画的当前点为添加动画效果之后的属性返回适当的值。FloatEvaluator 类演示了如何做到这一点:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
Keyframe 对象由时间值对组成,用于在动画的特定时间定义特定的状态。每个关键帧还可以用自己的插值器控制动画在上一关键帧时间和此关键帧时间之间的时间间隔内的行为。
要实例化 Keyframe 对象,您必须使用它的任一工厂方法(ofInt()、ofFloat() 或 ofObject())来获取类型合适的 。然后,通过调用 ofKeyframe() 工厂方法来获取 PropertyValuesHolder 对象。
获取对象后,您可以通过传入 PropertyValuesHolder 对象以及要添加动画效果的对象来获取 Animator。以下代码段演示了如何做到这一点:
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(5000);
动画
Java 专栏
SQL 专栏
数据结构与算法
Android学习专栏