基础知识点-动画
hi,大家好,我是爱吃香蕉的猴子,今天补习了一下android的属性动画,一直以来,动画的知识储备都不够,特意搜了几篇好的文章学习
转载推荐大家看原版文章
补间动画
- 补间动画能够帮我们实现对View的移动、缩放、旋转和淡入淡出,但这也仅仅局限于继承自View对象。
- 特点:View的位置没有改变
- onDraw()方法中绘制了 Point,可以对这个 Point 对象进行动画,又或者我只需要修改一个View的背景色的透明度,补间动画也只能望View兴叹。这就需要属性动画
- 缺点:补间动画只能改变View显示的状态,并没有修改 View 真正的属性,比如我们将一个按钮从屏幕上方移动到了屏幕下方,但是你如果在动画完成后点击Button显示的区域,这时候你会发现,无法点击,因为按钮的坐标属性并未得到修改。
属性动画
- 你希望View有一个颜色的切换动画;你希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因。比较常用的几个动画类:ValueAnimator 、ObjectAnimator 、和AnimatorSet, 其中ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集合,可以定义一组动画,它们使用起来也极其简单。
- ObjectAnimator改变一个对象的translationY属性,让其沿着Y轴向上平移一段距离:它的高度,该动画再默认时间内完成,动画的完成时间是可以定义的。想要更加灵活我们还可以定义插值器和估值器;
TextView tvTip = findViewById(R.id.tv_tip);
ObjectAnimator objectAnimator = ObjectAnimator
.ofFloat(tvTip, "scaleX", 1f, 1.5f);
objectAnimator.start();
- ValueAnimator 改变一个对象的背景色属性,典型的情形是改变View的背景色;
- 实现原理就是修改控件的属性值实现的动画,改变的是对象的真实属性。
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
// 持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animator) {
// 获得当前动画的进度值,整型,1-100之间
int currentValue = (Integer) animator.getAnimatedValue();
Log.d(TAG, "current value: " + currentValue);
// 获得当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = animator.getAnimatedFraction();
// 直接调用整型估值器通过比例计算出宽度,然后再设给Button
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
- AnimatorSet XML属性动画使用方法
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(myView, "rotationX", 0, 360)
...
);
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"
adnroid:valueTo="float | int | color"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"] />
</set>
理解插值器和估值器:
TimeInterpolator中文翻译就是时间插值器,它的作用就是根据时间流逝的百分比来计算出当前属性值改变的百分比, 系统预置的有LinearInterpolator线性插值器:匀速动画,AccelerateDecelerateInterpolator加速减速插值器:动画两头慢中间快和DecelerateInterpolator减速插值器:动画越来越慢。
TypeEvaluator:估值器,它的作用就是根据当前属性改变的百分比计算改变之后的属性值,系统预置的有IntEvaluator针对整形属性 、FloatEvaluator针对浮点型属性和ArgbEvaluator针对Color属性。
属性动画中的插值器和估值器很重要,他们是实现非匀速运动动画的重要手段。
补充知识: 动画默认的刷新率为10ms/帧,所以该动画将分5帧进行,我们来考虑第三帧(x=20, t=20ms), 当时间t=20ms的时候,时间流逝的百分比是0.5,以为着现在时间过了一半,那x应该改变多少呢? 这个就用插值器和估值器来确定。
举例:线性插值器
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
特点:输入值和返回值一样,因此插值器返回值是0.5,这就意味着x改变是0.5,这个时候插值器的工作完成。
再看一下估值器:
public class IntEvaluator implements TypeEvaluator<Integer> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value; should be of type <code>int</code> or
* <code>Integer</code>
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
evalute的三个参数分别表示估值小数、开始值和结束值,对应于我们的例子:0.5 0 40;整型估值返回20,这就是(x=20, t=20ms)的由来;
属性动画的监听器:
属性动画提供了监听器用于监听动画的播放过程,主要有接口: AnimatorUpdateListener 和 AnimatorListener;
public static interface AnimatorListener {
default void onAnimationStart(Animator animation, boolean isReverse) {
onAnimationStart(animation);
}
default void onAnimationEnd(Animator animation, boolean isReverse) {
onAnimationEnd(animation);
}
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
从AnimatorListener的定义可以看出,它可以监听动画的开始、结束、取消以及重复播放。同时为了方便开发,系统还提供了AnimatorListenerAdapter这个类,它是AnimatorListener的适配器类,这样我们就可以有选择的实现上的4个方法;
对任意属性做动画
实际问题: 给Button加一个动画,让Button的宽度变500px, view动画可以实现平移、旋转、缩放、不透明度。但是如果使用View来实现只是Button被放大而已,button上面的文本都被拉伸,故不是一个好的方式;
属性动画实现:
private void performAnimate() {
ObjectAnimator.ofInt(mButton, "width", 500).setDuration(5000).start();
}
@Override
public void onClick(View v) {
if (v == mButton) {
performAnimate();
}
}
属性动画要求动画作用的对象提供属性的get 和 set 方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。
暂写这些吧
Code的搬运工V1.0