Android 動畫詳解

此次主要就介紹android動畫,android動畫目前分爲三種形式,Tween Animation 這個只能應用於view對象上面的,Drawable Animation這個是幀動畫,就是相似咱們有一些列的圖片依次播放圖片時出現的動畫,Property Animation 這個是屬性動畫,這也是在android3.0以後引進的動畫,在手機的版本上是android4.0就可使用這個動畫,下面咱們主要就是針對這三種狀況進行介紹。java

 

Tween Animationandroid

這個動畫在Property Animation以前使用最多的,固然在android4.0以後也是有不少人使用這個動畫來弄一些簡單的動畫效果,Tween Animation主要是包括四種動畫實現效果:express

 

  • AlphaAniamtion:漸變效果,這個是一個透明度的動畫效果
AlphaAnimation(float fromAlpha,float toAlpha)

 這個就是AlphaAnimation的構造函數,fromAlpha表示的是動畫初始時的透明度,toAlpha表示的是動畫結束時的透明度,這個取值範圍是0~1,0表示的是徹底透明,1表示的是徹底不透明apache

 

  • 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倍canvas

pivotXType和pivotYType分別表示在X和Y軸上伸縮模式這裏有三個值:app

Animation.ABSOLUTE:這個表示的是絕對座標less

Animation.RELATIVE_TO_SELF:相對於本身的座標ide

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先執行,以後到xAnimatoryAnimatorxAnimator是同時執行的,執行完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());
                    }
                    
                });

動畫結束以後打印的信息以下

 

 這個時候咱們再使用x動畫以後

 

仍是同樣的,這個主要是由於這個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軸的動畫

相關文章
相關標籤/搜索