Android中有補件動畫,幀動畫和屬性動畫這幾種常見動畫。屬性動畫是3.0系統後推出的比較強大的動畫。可以實作生活中大多數常見的動畫功能。最近學習,用到了屬性動畫,結合源碼和一些參考做一個記錄。
1.基本使用
屬性動畫中常用到類ValueAnimator,ObjectAnimator,屬性動畫就是通過改變對象的屬性實作動畫,這兩個類完成了對象的屬性從初始值到結束的值的變化。
常用的方法:ofFloat(),ofInt(),ofObject();等。這些方法都有很多不同的重載方法,提供不同的參數實作差異的功能。
其中有一個:ValueAnimator bizerAnimator = ObjectAnimator.ofObject(typeEvalautor, param, param,param);這個需要傳入一個估值器對象(TypeEvaluator)
其他方法:
bizerAnimator.setEvaluator();//設定一個估值器
bizerAnimator.setRepeatCount();//設定重複執行次數
bizerAnimator.setRepeatMode();//設定動畫重複的模式
bizerAnimator.setTarget();//設定動畫添加一個對象
bizerAnimator.setInterpolator();//設定一個插值器
這裡插值器和估值器是實作一些複雜效果的關鍵。
基本使用舉例:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);
valueAnimator.setDuration(500);
valueAnimator.start();
一個基本的用法就是三行代碼,實作500毫秒從0到1的變化;其實還可以傳入多個參數,這個ofFloat()方法參數是邊長參數。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,0.6f,0.2f,1f);
valueAnimator.setDuration(500);
valueAnimator.start();
上面實作了從0到0.6到0.2再到1的變化。
ObjectAnimator類:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,"translationX",0f,200f,0f);
objectAnimator.setDuration(2000);
objectAnimator.start();
對一個ImageView 實作從起始位置到200px在到原始位置的變化,對應的:
"translationX"
是ImageView 的一個屬性,這個屬性在ImageView 中有個對應的set方法:
imageView.setTranslationX(0);
這裡需要注意的一點就是: 在對一個對象進行操作的時候,第一個參數是對象示例,第二個參數一定是對應對象的一個屬性并且有一個set方法去設定這個屬性。動畫執行過程就是通過這個屬性設定值的。
2.組合使用
組合使用就是把不同的動畫效果放一起執行,可以是先後執行,也可以同時執行,這是實作一些複雜效果的關鍵。組合使用通過AnimatorSet 來組合。
比如對上的圖檔添加第一個移動,透明度變化和旋轉三種動畫,組合執行:
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator translation = ObjectAnimator.ofFloat(imageView,"translationX",0f,300f,0f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView,"alpha",1f,0f,1f);
ObjectAnimator rotationY = ObjectAnimator.ofFloat(imageView,"rotationY",0f,360f);
//animatorSet.playSequentially(translation,alpha,rotationY);//按順序執行位置移動,透明度變化,和旋轉三個動畫效果。
//animatorSet.play(translation).with(alpha).before(rotationY);//執行translation同時執行alpha 設定,在執行rotationY之前。
animatorSet.playTogether(translation,alpha,rotationY);//三個同時執行
animatorSet.setDuration(3000);
animatorSet.start();
以上代碼建立了三個通話效果,通過不同的方法組合不同的執行效果。
知道了這些,我們還可以通過操作其他的對象屬性作出其他的效果來。
屬性動畫的基本使用就是這些,如果代碼操作不友善還可以寫xml,在項目中使用。直接在代碼中加載設定執行。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="1000"
android:propertyName="translationX"
android:valueFrom="0dp"
android:valueTo="100dp"
android:valueType="floatType" />
<objectAnimator
android:duration="1000"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
<!--<objectAnimator-->
<!--android:duration="1000"-->
<!--android:propertyName="translationX"-->
<!--android:valueFrom="100dp"-->
<!--android:valueTo="0dp"-->
<!--android:valueType="floatType" />-->
</set>
加載執行:
Animator animator = AnimatorInflater.loadAnimator(this,R.animator.animator1);
animator.setTarget(imageView);
animator.start();
仔細的看看xml代碼,其實沒有直接java建立動畫友善,java中屬性在一個動畫可以重複操作如:位置移動,從左到右,在到左。
3.實際應用
如果還需要其他的複雜效果就要通過我們自定義來實作了。比如網絡中的一些彈跳效果,水波效果等,這裡了解一些概念。
估值器:
所謂估值器從名稱上一直沒有了解明白。實際就是實作一個邏輯處理的方法。
估值器實作了一個接口重寫了evaluate()方法。
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);
}
看幾個個系統提供的估值器代碼:
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 * (v1 - v0)</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));
}
}
上面是一個整數估值器,evaluate();方法就是進行一個計算處理在傳回去。
public class PointFEvaluator implements TypeEvaluator<PointF> {
private PointF mPoint;
public PointFEvaluator() {
}
public PointFEvaluator(PointF reuse) {
mPoint = reuse;
}
/**
* This function returns the result of linearly interpolating the start and
* end PointF values, with <code>fraction</code> representing the proportion
* between the start and end values. The calculation is a simple parametric
* calculation on each of the separate components in the PointF objects
* (x, y).
*
* <p>If {@link #PointFEvaluator(android.graphics.PointF)} was used to construct
* this PointFEvaluator, the object returned will be the <code>reuse</code>
* passed into the constructor.</p>
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start PointF
* @param endValue The end PointF
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float x = startValue.x + (fraction * (endValue.x - startValue.x));
float y = startValue.y + (fraction * (endValue.y - startValue.y));
if (mPoint != null) {
mPoint.set(x, y);
return mPoint;
} else {
return new PointF(x, y);
}
}
}
PointFEvaluator 中evaluate()方法對兩個PointF進行處理,最後傳回。從上面看,估值器就是對指定的一些參數按照我們的需求,重新處理生成一個新的參數給動畫執行。
插值器:
估值器也是實作了一個接口和方法。
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
系統提供了一些常用的插值器:
線性插值器,讓動畫成線性運動執行。對于接口的方法getInterpolation()直接傳回資料,沒有處理。
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();
}
}
加速插值器,動畫逐漸加速。從代碼看,getInterpolation()方法傳回值是一個進行了乘法或者多次幂函數計算,從數學上說這就是一個幂函數曲線加速。
Math.pow(input, mDoubleFactor);
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
private final float mFactor;
private final double mDoubleFactor;
public AccelerateInterpolator() {
mFactor = 1.0f;
mDoubleFactor = 2.0;
}
/**
* Constructor
*
* @param factor Degree to which the animation should be eased. Seting
* factor to 1.0f produces a y=x^2 parabola. Increasing factor above
* 1.0f exaggerates the ease-in effect (i.e., it starts even
* slower and ends evens faster)
*/
public AccelerateInterpolator(float factor) {
mFactor = factor;
mDoubleFactor = 2 * mFactor;
}
public AccelerateInterpolator(Context context, AttributeSet attrs) {
this(context.getResources(), context.getTheme(), attrs);
}
/** @hide */
public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
TypedArray a;
if (theme != null) {
a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
} else {
a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
}
mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
mDoubleFactor = 2 * mFactor;
setChangingConfiguration(a.getChangingConfigurations());
a.recycle();
}
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
}
通過上述系統代碼的檢視我們大緻了解了,插值器就是通過一些數學計算,讓目前時間的動畫值改變,進而達到一定效果。
總的來說,估值器是處理了動畫目前的資料,而插值器就對目前執行速度操作,達到一定效果。後邊在對實際的自定義做練習。
參考資料:
http://www.jianshu.com/p/02deec7bf8f0
http://www.cnblogs.com/mengdd/p/3346003.html