這個動畫在Property Animation之前使用最多的,當然在android4.0之後也是有很多人使用這個動畫來弄一些簡單的動畫效果,Tween Animation主要是包括四種動畫實現效果:
AlphaAniamtion:漸變效果,這個是一個透明度的動畫效果
1
AlphaAnimation(float fromAlpha,float toAlpha)
這個就是AlphaAnimation的構造函數,fromAlpha表示的是動畫初始時的透明度,toAlpha表示的是動畫結束時的透明度,這個取值范圍是0~1,0表示的是完全透明,1表示的是完全不透明
ScaleAnimation:圖片進行放大縮小的動畫效果,
ScaleAnimation(float fromX, float toX, float fromY,float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
上面就是這個Scale參數的情況,這個參數是最多的,fromX:起始X坐標上的伸縮尺寸,toX:結束X坐標上的伸縮尺寸,fromY:起始Y坐標上的伸縮尺寸,toY:結束Y坐標上的伸縮尺寸,關於這個伸縮尺寸,0表示的就是看不見,1表示原始大小,依此類推,1.5表示的就是1.5倍
pivotXType和pivotYType分別表示在X和Y軸上伸縮模式。這裡有三個值:
Animation.ABSOLUTE:這個表示的是絕對坐標
Animation.RELATIVE_TO_SELF:相對於自己的坐標
Animation.RELATIVE_TO_PARENT:相對於父控件
上面這些說的都是這個動畫效果相對於哪一個點來進行變化的,Animation.RELATIVE_TO_SELF這個就相對於自己的坐標,就是說這個坐標原始坐標是在你設置view的左上角,Animation.RELATIVE_TO_PARENT相對於父控件的坐標,這個大多數指的就是手機上的坐標原點。Animation.ABSOLUTE絕對坐標說的就是具體相對哪個一個點,比如(100,200),就是表示相對坐標點在(100,200)這個點來進行動畫。
pivotXValue和pivotYValue值就是相對上面的值設置的,表示的是相對於哪一個點來進行放大縮小的動畫,對於Animation.RELATIVE_TO_SELF和Animation.RELATIVE_TO_PARENT
(0,0)表示的是原點,(0.5f,0.5f)表示的中間點這個對於Animation.RELATIVE_TO_SELF相對於view控件的中間點,Animation.RELATIVE_TO_PARENT就是值該view上父控件的中間點,(1,1)表示的就是右下角的坐標。這個我們可以多多試試就知道效果了。
一般情況下使用是Animation.RELATIVE_TO_SELF,選擇點是(0.5f,0.5f)就是該view的中間點,這樣圖片變化看起來不會產生很奇怪的感覺。
TranslateAnimation:view在水平方向和垂直方向進行移動動畫效果
TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta)
fromXDelta和fromYDelta分別表示在X和Y軸上面的起始坐標,(0,0)這個表示的就是當前view的坐標,toXDelta和toYDelta分別表示最終目標,如果只是X軸移動或者Y軸移動,那麼可以把對應不移動的坐標設置為0。
RotateAnimation:旋轉動畫效果
RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue)
fromDegrees和toDegrees分別表示的起始角度和結束角度,比如(0,45)這個就是表示從默認狀態旋轉到45度的意思。剩下的參數上面已經介紹過來,比如下面的代碼:
RotateAnimation rotate=new RotateAnimation(0, 50, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
表示就是從默認狀態旋轉到50度,旋轉的中心點就是這個view的中心點(Animation.RELATIVE_TO_SELF表示的以自身為參考點,0.5f表示就是一般)
上面介紹就是這個Tween Animation動畫效果,分別是透明度的變化,放大縮小,移動以及旋轉動畫效果,這些動畫除了上面的構造函數之外當然還有一些公共的其它方法,下面就介紹一下:
setDuration(long durationMillis)
這個表示的是設置動畫的顯示時間,就是這個動畫從初始狀態到結束狀態所需要的時間,durationMillis參數為動畫顯示時間的長短,單位是毫秒。
setStartOffset(long startOffset)
這個表示的是動畫的開始時間,startOffset表示就是動畫的開始時間,單位毫秒(有時候我們在startAnimation之後可能不希望立即取執行這個動畫,需要等待一會再進行動畫就可以使用這個
setFillAfter(boolean fillAfter)
這個表示的動畫結束之後是否保留結束的位置,這個值默認是flase表示動畫結束之後不保留動畫的位置,就是說在我們進行動畫效果結束之後又會自動恢復到原始的狀態,true表示就是保留動畫結束時的狀態,這個值一般都是要設置為true的
startAnimation(Animation animation)
這個是在view對象上使用的,表示開始進行動畫,參數就是我們上面說的那四種(注意上面的四種類型都是繼承於Animation的),比如我現在有一個ImageView對象image,那麼我現在要開始動畫時就是用imageView.startAnimation(rotateAnimation);就可以進行動畫了,
setInterpolator(Interpolator i)
這個表示的設置動畫的變化速度,這裡android提供很多類型的Interpolator類型的變化器
1。setInterpolator(new AccelerateInterpolator(float factor):這個AccelerateInterpolator表示的是加速,factor參數可以設置為加速的倍數,數值越大動畫的速度越快,當然也可以是默認的new AccelerateInterpolator()默認這個參數為1。我們來看一下源碼:
復制代碼
/**
* An interpolator where the rate of change starts out slowly and
* and then accelerates.
*
*/
public class AccelerateInterpolator implements Interpolator {
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) {
TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
mDoubleFactor = 2 * mFactor;
a.recycle();
}
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
}
復制代碼
上面那個就是AccelerateInterpolator的源碼,這個源碼中有兩個構造函數一個帶參數一個不帶參數的,從上面代碼中getInterpolation這個方法是最重要的,那麼跟蹤一下這個方法調用是在Animation.java類中的getTransformation()方法
復制代碼
public boolean getTransformation(long currentTime, Transformation outTransformation) {
if (mStartTime == -1) {
mStartTime = currentTime;
}
final long startOffset = getStartOffset();
final long duration = mDuration;
float normalizedTime;
if (duration != 0) {
normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
(float) duration;
} else {
// time is a step-change with a zero duration
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
final boolean expired = normalizedTime >= 1.0f;
mMore = !expired;
if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
if (!mStarted) {
fireAnimationStart();
mStarted = true;
if (USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
。。。。。。。。。
return mMore;
}
復制代碼
上面就是getTransformation()方法,在這個方法中也看到之前設置的getStartOffset()以及mDuration等等,在下面發現這麼一句話
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);mInterpolator對象創建也是在這個類裡面
public void setInterpolator(Interpolator i) {
mInterpolator = i;
}
看上面就是我們代碼中設置的,那麼來看看這個getInterpolation裡面參數的值,從上面源碼中知道mFillEnabled和mCycleFlip默認值都是flase,一般情況下我們都不會去設置這兩個值都是取默認值的,if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);這個設置了normalizedTime的值,就是下面要用做getInterpolation參數值,從上面的代碼中可以發現normalizedTime這個值是不小於0的,Math.max(Math.min(normalizedTime, 1.0f), 0.0f)表示取值范圍就是0~1,也就是手這個getInterpolation(float input)這個input參數的變化就是在指定的動畫事件內從0到1遞增變化。
我們來看看Interpolator這個類
復制代碼
package android.view.animation;
import android.animation.TimeInterpolator;
/**
* An interpolator defines the rate of change of an animation. This allows
* the basic animation effects (alpha, scale, translate, rotate) to be
* accelerated, decelerated, repeated, etc.
*/
public interface Interpolator extends TimeInterpolator {
// A new interface, TimeInterpolator, was introduced for the new android.animation
// package. This older Interpolator interface extends TimeInterpolator so that users of
// the new Animator-based animations can use either the old Interpolator implementations or
// new classes that implement TimeInterpolator directly.
}
復制代碼
再看這個TimeInterpolator類
復制代碼
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.animation;
/**
* A time interpolator defines the rate of change of an animation. This allows animations
* to have non-linear motion, such as acceleration and deceleration.
*/
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);
}
復制代碼
從這段代碼中我們得出結論就是所有的變化器都是繼承於Interpolator接口,而且都實現了float getInterpolation(float input);這個方法,那麼我們就要弄清楚這個getTransformation()方法在哪裡調用,我們說過StartAnimation是view對象調用那麼我們在View.java裡面
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
這段代碼中最後一句就是更新,看一下
復制代碼
/**
* This method is called by ViewGroup.drawChild() to have each child view draw itself.
* This draw() method is an implementation detail and is not intended to be overridden or
* to be called from anywhere else other than ViewGroup.drawChild().
*/
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
boolean more = false;
final boolean childHasIdentityMatrix = hasIdentityMatrix();
final int flags = parent.mGroupFlags;
if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) {
parent.getChildTransformation().clear();
parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
Transformation transformToApply = null;
boolean concatMatrix = false;
boolean scalingRequired = false;
boolean caching;
int layerType = getLayerType();
final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
(flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
caching = true;
// Auto-scaled apps are not hw-accelerated, no need to set scaling flag on DisplayList
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
} else {
caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
}
final Animation a = getAnimation();
if (a != null) {
more = drawAnimation(parent, drawingTime, a, scalingRequired);
concatMatrix = a.willChangeTransformationMatrix();
if (concatMatrix) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
transformToApply = parent.getChildTransformation();
} else {
。。。。。。。。。。。。。。。。。。。。。。。
復制代碼
上面這段代碼中有這麼一句話 more = drawAnimation(parent, drawingTime, a, scalingRequired),這個函數就是
復制代碼
private boolean drawAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
Transformation invalidationTransform;
final int flags = parent.mGroupFlags;
final boolean initialized = a.isInitialized();
if (!initialized) {
a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
onAnimationStart();
}
final Transformation t = parent.getChildTransformation();
boolean more = a.getTransformation(drawingTime, t, 1f);
。。。。。。。。。。。。。。。。。。。。。。。。。
復制代碼
看到上面的drawAnimation方法中就有a.getTransformation(drawingTime, t, 1f);這個方法,我們也就明白了這個getTransformation()方法是在startAnimation()之後調用的。
2。setInterpolator(new AccelerateDecelerateInterpolator()):這個AccelerateDecelerateInterpolator表示的是先加速後減速的動畫
復制代碼
/**
* An interpolator where the rate of change starts and ends slowly but
* accelerates through the middle.
*
*/
public class AccelerateDecelerateInterpolator implements Interpolator {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
}
復制代碼
3。setInterpolator(new DecelerateInterpolator(float factor)):這個表示的就是減速,factor和上面的加速參數是一個意思,只不過作用是相反的,也可以不帶參數new DecelerateInterpolator()這樣
復制代碼
/**
* An interpolator where the rate of change starts out quickly and
* and then decelerates.
*
*/
public class DecelerateInterpolator implements Interpolator {
public DecelerateInterpolator() {
}
/**
* Constructor
*
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
* an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
* ease-out effect (i.e., it starts even faster and ends evens slower)
*/
public DecelerateInterpolator(float factor) {
mFactor = factor;
}
public DecelerateInterpolator(Context context, AttributeSet attrs) {
TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);
mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);
a.recycle();
}
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
result = (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
return result;
}
private float mFactor = 1.0f;
}
復制代碼
4。setInterpolator(new CycleInterpolator()):動畫循環播放特定次數,速率改變沿著正弦曲線
復制代碼
/**
* Repeats the animation for a specified number of cycles. The
* rate of change follows a sinusoidal pattern.
*
*/
public class CycleInterpolator implements Interpolator {
public CycleInterpolator(float cycles) {
mCycles = cycles;
}
public CycleInterpolator(Context context, AttributeSet attrs) {
TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator);
mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f);
a.recycle();
}
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
private float mCycles;
}
復制代碼
5。setInterpolator(new LinearInterpolator()):表示勻速
復制代碼
/**
* An interpolator where the rate of change is constant
*
*/
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
}
復制代碼
6。setInterpolator(new OvershootInterpolator()) 超越,最後超出目的值然後緩慢改變到目的值
復制代碼
/**
* An interpolator where the change flings forward and overshoots the last value
* then comes back.
*/
public class OvershootInterpolator implements Interpolator {
private final float mTension;
public OvershootInterpolator() {
mTension = 2.0f;
}
/**
* @param tension Amount of overshoot. When tension equals 0.0f, there is
* no overshoot and the interpolator becomes a simple
* deceleration interpolator.
*/
public OvershootInterpolator(float tension) {
mTension = tension;
}
public OvershootInterpolator(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.OvershootInterpolator);
mTension =
a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);
a.recycle();
}
public float getInterpolation(float t) {
// _o(t) = t * t * ((tension + 1) * t + tension)
// o(t) = _o(t - 1) + 1
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}
復制代碼
7。setInterpolator(new BounceInterpolator()):跳躍,快到目的值時值會跳躍,如目的值100,後面的值可能依次為85,77,70,80,90,100
復制代碼
/**
* An interpolator where the change bounces at the end.
*/
public class BounceInterpolator implements Interpolator {
public BounceInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public BounceInterpolator(Context context, AttributeSet attrs) {
}
private static float bounce(float t) {
return t * t * 8.0f;
}
public float getInterpolation(float t) {
// _b(t) = t * t * 8
// bs(t) = _b(t) for t < 0.3535
// bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
// bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
// bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
// b(t) = bs(t * 1.1226)
t *= 1.1226f;
if (t < 0.3535f) return bounce(t);
else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
else return bounce(t - 1.0435f) + 0.95f;
}
}
復制代碼
8。setInterpolator(new AnticipateOvershootInterpolator()):反向加超越,先向相反方向改變,再加速播放,會超出目的值然後緩慢移動至目的值
復制代碼
/**
* An interpolator where the change starts backward then flings forward and overshoots
* the target value and finally goes back to the final value.
*/
public class AnticipateOvershootInterpolator implements Interpolator {
private final float mTension;
public AnticipateOvershootInterpolator() {
mTension = 2.0f * 1.5f;
}
/**
* @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
* there is no anticipation/overshoot and the interpolator becomes
* a simple acceleration/deceleration interpolator.
*/
public AnticipateOvershootInterpolator(float tension) {
mTension = tension * 1.5f;
}
/**
* @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
* there is no anticipation/overshoot and the interpolator becomes
* a simple acceleration/deceleration interpolator.
* @param extraTension Amount by which to multiply the tension. For instance,
* to get the same overshoot as an OvershootInterpolator with
* a tension of 2.0f, you would use an extraTension of 1.5f.
*/
public AnticipateOvershootInterpolator(float tension, float extraTension) {
mTension = tension * extraTension;
}
public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
a.recycle();
}
private static float a(float t, float s) {
return t * t * ((s + 1) * t - s);
}
private static float o(float t, float s) {
return t * t * ((s + 1) * t + s);
}
public float getInterpolation(float t) {
// a(t, s) = t * t * ((s + 1) * t - s)
// o(t, s) = t * t * ((s + 1) * t + s)
// f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
// f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
}
復制代碼
9。setInterpolator(new AnticipateInterpolator()):反向 ,先向相反方向改變一段再加速播放
復制代碼
/**
* An interpolator where the change starts backward then flings forward.
*/
public class AnticipateInterpolator implements Interpolator {
private final float mTension;
public AnticipateInterpolator() {
mTension = 2.0f;
}
/**
* @param tension Amount of anticipation. When tension equals 0.0f, there is
* no anticipation and the interpolator becomes a simple
* acceleration interpolator.
*/
public AnticipateInterpolator(float tension) {
mTension = tension;
}
public AnticipateInterpolator(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AnticipateInterpolator);
mTension =
a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
a.recycle();
}
public float getInterpolation(float t) {
// a(t) = t * t * ((tension + 1) * t - tension)
return t * t * ((mTension + 1) * t - mTension);
}
}
復制代碼
就上面這麼多了,按照上面的代碼我們也可以自定義我們符合我們自己的Interpolator,定義方法就是寫一個類繼承於Interpolator接口,並且去實現getInterpolation()方法,在該方法裡面做相應的運算。
常用的方法就上面這些,來看一下一個ScaleAnimation用法,其它類似:
復制代碼
private ScaleAnimation scale(){
ScaleAnimation scaleAnimation=new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
scaleAnimation.setStartOffset(0);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setFillAfter(true);
return scaleAnimation;
}
復制代碼
開啟這個動畫在一個按鈕上面
復制代碼
imageView=(ImageView) findViewById(R.id.image);
scaleBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
imageView.startAnimation(scale());
}
});
復制代碼
上面這個就實現圖片放大縮小的效果
如果我們想要實現兩種以上的動畫如何處理呢,這個時候我們就可以使用AnimationSet這個類實現多個動畫疊加效果,
AnimationSet(boolean shareInterpolator);
這個參數設為false表示可以在每個添加到AnimationSet中的Animation都使用Interpolator,且效果都能清楚的觀察。設置為true如果在添加到AnimationSet中的Animation設置Interpolator將無效果,通過設置AnimationSet的Interpolator可以設置所有動畫的Interpolator且所有動畫的Interpolator都一樣。
復制代碼
private AnimationSet allAnimation(){
AnimationSet set=new AnimationSet(boolean shareInterpolator);
TranslateAnimation translate=new TranslateAnimation(0, 100, 0, 100);
RotateAnimation rotate=new RotateAnimation(0, 50, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
set.addAnimation(translate);
set.addAnimation(rotate);
set.setInterpolator(new AnticipateOvershootInterpolator());
set.setFillAfter(true);
set.setDuration(1000);
set.setStartOffset(100);
return set;
}
復制代碼
我們看到addAnimation就是添加動畫效果,其它方法和那個是一樣的
我們在使用的過程有時候需要監聽動畫的開始和結束,AnimationListener這個就是動畫監聽
復制代碼
set.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
}
});
復制代碼
看上面的意思就會明白那個是表示動畫的開始,那個是動畫結束了
這個我們可以在res/anim目錄中通過xml來寫動畫
復制代碼
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="1000"
/>
<translate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="100"
android:fromYDelta="0"
android:toYDelta="100"
android:startOffset="50"
android:duration="1000"
/>
</set>
復制代碼
上面就是xml寫的,那麼如何加載呢?看下面的代碼
Animation an=AnimationUtils.loadAnimation(AnimationTest.this, R.anim.itchqanimator);
imageView.startAnimation(an);
這個就是加載xml裡面的動畫的
Property Animation
這個是屬性動畫,是android4.0引入手機中(android 3.0中就有了只是3.0主要的在平板電腦上使用的),我們上面講解的那種tween Animation動畫改變的是view繪制,而沒有改變View對象本身,比如,你有一個Button,坐標 (100,100),Width:200,Height:50,而你有一個動畫使其變為Width:100,Height:100,你會發現動畫過程中觸 發按鈕點擊的區域仍是(100,100)-(300,150)。而在Property Animation中,改變的是對象的實際屬性,而且Property Animation不止可以應用於View,還可以應用於任何對象。
ValueAnimator類就是這個的包含Property Animation的動畫所以核心功能,如動畫的時間,開始,結束的屬性值等等,當時對於ValueAnimator來說我們一般都不會直接使用這個,我們都是直接使用ValueAnimator的子類就是ObjectAnimator。
ObjectAnimator是繼承於ValueAnimator的,使用這個ObjectAnimator是有條件限制的
1。對象應該有一個setter函數:set<PropertyName>(駝峰命名法),這個命名法可以上網查一下,很容易理解的
2。創建ObjectAnimation對象一般是
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 1f,0f);
像ofFloat之類的工場方法,第一個參數為對象名(這個也就是我們的view類了),第二個為屬性名,後面的參數為可變參 數,如果values…參數只設置了一個值的話,那麼會假定為目的值,屬性值的變化范圍為當前值到目的值,為了獲得當前值,該對象要有相應屬性的 getter方法:get<PropertyName>
3。如果有getter方法,其應返回值類型應與相應的setter方法的參數類型一致。正常情況駝峰命名法都是get和set方法對應的出現
復制代碼
valueBtn=(Button) findViewById(R.id.valueAnimation);
valueBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 1f,0f);
objectAnimator.setDuration(1000);
objectAnimator.start();
}
});
復制代碼
這個就是ObjectAnimator簡單的用法,通過這個我們也可以監聽動畫的開始和結束,上面有介紹過AnimatorListener的監聽,如下:
復制代碼
objectAnimator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
復制代碼
當是我們有時候不需要取監聽動畫的取消或者重復,這些代碼在這裡顯然是多余的,這個時候我們就可以使用AnimatorListenerAdapter這個適配器來進行監聽了,如下
復制代碼
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
}
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationStart(animation);
}
});
復制代碼
這個就只關心我們的動畫開始和介紹,其它就不需要了,代碼看起來簡潔了很多。ObjectAnimator當然也有setInterpolator()和setStartDelay()等一系列方法,這些的話就和我們上面的說的tween Animation動畫方法是一樣的。如果我們想要同時實現很多個動畫就需要AnimatorSet這個類來實現,如下代碼:
復制代碼
AnimatorSet set=new AnimatorSet();
ObjectAnimator alphaAnimator=ObjectAnimator.ofFloat(valueBtn, "alpha", 0f,1f);
ObjectAnimator xAnimator=ObjectAnimator.ofFloat(valueBtn, "translationX", 0f,5f,10f);
ObjectAnimator yAnimator=ObjectAnimator.ofFloat(valueBtn, "translationY", 0f,5f,10f);
ObjectAnimator rotateYAnimator=ObjectAnimator.ofFloat(valueBtn, "rotationX", 0f,90f);
set.play(alphaAnimator).before(xAnimator);
set.play(xAnimator).with(yAnimator);
set.play(yAnimator).after(rotateYAnimator);
set.setDuration(2000);
set.start();
復制代碼
上面就是使用AnimatorSet方法,這個方法提供了before,with,after方法,按上面代碼的意思就是alphaAnimator先執行,之後到xAnimator,yAnimator和xAnimator是同時執行的,執行完yAnimator和xAnimator之後就執行rotateYAnimator,看上面的字面意思也很容易理解了。
在實現過程中經常使用一些動畫屬性:
1。translationX,translationY,x,y
這些translationX和x,TranslationY和y是用區別的,下面來看看這個區別在哪裡(我們這裡以X坐標為例)
valueBtn=(Button) findViewById(R.id.valueAnimation);
Log.i("itchq", "valueBtn.getLeft()="+valueBtn.getLeft());
Log.i("itchq", "valueBtn.getX()="+valueBtn.getX());
Log.i("itchq", "valueBtn.getTranslationX()="+valueBtn.getTranslationX());
上面的代碼中看一默認打印的信息是:
這個默認都是為0的,當我使用translationX動畫之後
復制代碼
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueBtn, "translationX", 0f,100f);
objectAnimator.setDuration(1000);
objectAnimator.start();
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
Log.i("itchq", "valueBtn.getLeft()="+valueBtn.getLeft());
Log.i("itchq", "valueBtn.getX()="+valueBtn.getX());
Log.i("itchq", "valueBtn.getTranslationX()="+valueBtn.getTranslationX());
}
});
還是一樣的,這個主要是因為這個getLeft為0,那麼我們這個時候把getLeft設置為20時,當是translationX時動畫之後打出的log是
這個時候的x不再是100了而是120了,再設置為x,看一下結果
這個時候的getTranslationX()不再是100了,而是80,所以無論啥樣應用動畫,getLeft的值是不會變的,而TranslationX的值是為最終位置於布局時初始位置的差,即“最終位置-getLeft()",而x為最終位置之和,即”getLeft()+getTranslationX()“,所以當getLeft為0的時候就會發現兩個值是相等的。
2。rotation,rotationX,rotationY:旋轉,rotation用於2D旋轉角度,3D中用到後兩個
3。scaleX,scaleY:縮放
4。alpha:透明度
Keyframe
keyFrame是一個 時間/值 對,通過它可以定義一個在特定時間的特定狀態,而且在兩個keyFrame之間可以定義不同的Interpolator,就相當多個動畫的拼接,第一個動 畫的結束點是第二個動畫的開始點。KeyFrame是抽象類,要通過ofInt(),ofFloat(),ofObject()獲得適當的 KeyFrame,然後通過PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對象,如以下代碼:
復制代碼
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator widthAnim = ObjectAnimator.ofPropertyValuesHolder(valueBtn, pvhRotation);
widthAnim.setDuration(2000);
widthAnim.start();
復制代碼
上述代碼的意思為:設置valueBtn對象的width屬性值使其:
開始時 Width=400
動畫開始1/4時 Width=200
動畫開始1/2時 Width=400
動畫開始3/4時 Width=100
動畫結束時 Width=500
第一個參數為時間百分比,第二個參數是在第一個參數的時間時的屬性值。定義了一些Keyframe後,通過PropertyValuesHolder類的方法ofKeyframe封裝,然後通過ObjectAnimator.ofPropertyValuesHolder獲得Animator。
PropertyValuesHolder
如果需要對一個View的多個屬性進行動畫可以用ViewPropertyAnimator類,該類對多屬性動畫進行了優化,會合並一些invalidate()來減少刷新視圖
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator x_yAnimator=ObjectAnimator.ofPropertyValuesHolder(valueBtn, pvhX, pvhY);
x_yAnimator.setDuration(1000);
x_yAnimator.start();
上面這段代碼就是同時進行X軸和Y軸的動畫