1.属性动画介绍
解释属性
ImageView imageView = new ImageView(this);
imageView.getBottom();
上述代码创建了一个ImageView的对象,同时调用getBottom()方法,获取到值,而这个值是ImageView类中变量mBottom的值:
protected int mBottom;
这个mBottom就是ImageView对象的一个属性。
属性动画
属性动画就是通过改变对象的属性的值来产生动画效果,比如说改变ImageView的宽、高、位置的属性值来生成一些位移,拉伸动画。属性动画是Android 3.0 (API Level 11) 引入的。虽然之前的补间动画改变了它所作用的View 的外观,但并没有改变对象的本身;而属性动画却直接改变了他所作用的对象的属性。因此,我们可以在视觉或者其他方面修改任意对象的任意属性,通过使用一个属性动画生成器,在一个给定时间内使用我们选择的差值算法将该属性从一个值转换成另一个值。这个属性可以是任意对象,从常规的整型、浮点型到复杂的类对象实例都可以,目标属性甚至可以是不用代表视觉的属性。
这是一个非常强大的工具,可以作用在任何的事物上,从简单的View效果,如移动、缩放、View的淡入淡出,到复杂的动画,如运行时的布局改变、曲线变换。
2.属性动画相关类介绍
在介绍如何创建属性动画之前,我们先来了解下属性动画涉及到的类以及它们之间的关系,这样我们就能知晓属性动画是如何创建的。
2.1 类型估值器Evaluator
理解类型估值器Evaluator
类型估值器Evaluator是指根据时间流逝的百分比计算出当前属性的值。
我们给某个对象设置了一段时间长度为10秒的动画
对象中还有个属性 int x; 而这个动画就是改变属性 x 的值
我们设定这样的一段动画,0到3秒,x由10到50,4到8秒,x的值又由50减到30,9到10秒,x值由30变到90.
而Evaluator就是根据这三段不同的时间间隔和x属性值的变化,确定出每一毫秒,x的具体值,并应用在对象上。
介绍类型估值器Evaluator
它的接口定义是TypeEvaluator,其中定义了evaluate()方法,供不同类型的子类实现。
/**
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
* allow developers to create animations on arbitrary property types, by allowing them to supply
* custom evaluators for types that are not automatically understood and used by the animation
* system.
*
* @see ValueAnimator#setEvaluator(TypeEvaluator)
*/
public interface TypeEvaluator<T> {
/**
* 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.
* @param endValue The end value.
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);
}
常见的实现类有:IntEvaluator、FloatEvaluator、ArgbEvaluator等。下面我们来看一下ArgbEvaluator 的具体实现,可以看到实现逻辑很简单,就是根据输入的初始值和结束值及一个进度比,计算出每一个进度对应的 ARGB 值。
package android.animation;
/**
* This evaluator can be used to perform type interpolation between integer
* values that represent ARGB colors.
*/
public class ArgbEvaluator implements TypeEvaluator {
private static final ArgbEvaluator sInstance = new ArgbEvaluator();
/**
* Returns an instance of <code>ArgbEvaluator</code> that may be used in
* {@link ValueAnimator#setEvaluator(TypeEvaluator)}. The same instance may
* be used in multiple <code>Animator</code>s because it holds no state.
* @return An instance of <code>ArgbEvalutor</code>.
*
* @hide
*/
public static ArgbEvaluator getInstance() {
return sInstance;
}
/**
* This function returns the calculated in-between value for a color
* given integers that represent the start and end values in the four
* bytes of the 32-bit int. Each channel is separately linearly interpolated
* and the resulting calculated values are recombined into the return value.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue A 32-bit int value representing colors in the
* separate bytes of the parameter
* @param endValue A 32-bit int value representing colors in the
* separate bytes of the parameter
* @return A value that is calculated to be the linearly interpolated
* result, derived by separating the start and end values into separate
* color channels and interpolating each one separately, recombining the
* resulting values in the same way.
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
float startA = ((startInt >> 24) & 0xff) / 255.0f;
float startR = ((startInt >> 16) & 0xff) / 255.0f;
float startG = ((startInt >> 8) & 0xff) / 255.0f;
float startB = ( startInt & 0xff) / 255.0f;
int endInt = (Integer) endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = ( endInt & 0xff) / 255.0f;
// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);
endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);
// compute the interpolated color in linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}