4.動畫視圖

4.1 問題

應(yīng)用程序要讓視圖對象運動起來酷愧,實現(xiàn)變化或其他特效度秘。

4.2 解決方案

(API Level12)
ObjectAnimator實例广鳍,例如ViewPropertyAnimator,可以用來操作View對象的屬性说莫,例如視圖的位置或旋轉(zhuǎn)。ViewPropertyAnimation是通過View.animate()獲得的膝蜈,然后根據(jù)動畫的特征進(jìn)行修改。通過這個API進(jìn)行的修改會影響到View對象本身的真實屬性熔掺。

4.3 實現(xiàn)機制

ViewPropertyAnimation是對視圖內(nèi)容制作動畫的最便利方法饱搏。此API的工作方式就像生成器一樣,所有對不同屬性修改的調(diào)用都可以連接起來組成一個動畫置逻。在當(dāng)前線程的Looper的相同迭代中推沸,對ViewPropertyAnimation的所有調(diào)用都會匯集到一個動畫中。以下兩個代碼演示了一個簡單的視圖過渡Activity券坞。
res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/toggleButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Click to Toggle" />
    <View
        android:id="@+id/theView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#AAA" />
</LinearLayout>

使用了ViewPropertyAnimation的Activity

public class AnimateActivity extends Activity implements View.OnClickListener {

    private View mViewToAnimate;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button button = (Button)findViewById(R.id.toggleButton);
        button.setOnClickListener(this);
        
        mViewToAnimate = findViewById(R.id.theView);
    }
    
    @Override
    public void onClick(View v) {
        if(mViewToAnimate.getAlpha() > 0f) {
            //如果視圖可見鬓催,將其從右側(cè)滑出
            mViewToAnimate.animate().alpha(0f).translationX(500f);
        } else {
            //如果視圖是隱藏的,原地做漸顯動畫
            //Property Animations會實際修改視圖恨锚,因此必須首先恢復(fù)視圖的位置
            mViewToAnimate.setTranslationX(0f);
            mViewToAnimate.animate().alpha(1f);
        }
    }
}

在這個示例中宇驾,滑動動畫和漸顯動畫是通過alpha和translationX(這個過渡值需要足夠大才能夠讓視圖移除屏幕)屬性一起實現(xiàn)的。我們不需要將這些方法調(diào)用鏈接到一起猴伶,從而組成一個動畫课舍。即使我們在不同的地方調(diào)用菌瘫,它們還是會一起執(zhí)行,因為它們都是在主線程的Looper的相同迭代中設(shè)置的布卡。
注意雨让,這里我們首先恢復(fù)了View的過渡屬性,然后運行了沒有滑動效果的漸顯動畫忿等。這是因為屬性動畫會修改視圖本身栖忠,而不只是暫時地繪制(之前的動畫API的機制)。如果不恢復(fù)這個屬性贸街,依然會有漸顯動畫庵寞,但會在屏幕外右側(cè)1000像素處進(jìn)行。

1.ObjectAnimation

雖然ViewPropertyAnimation可以很方便且快速地實現(xiàn)簡單的屬性動畫薛匪,但對于一些更加復(fù)雜的工作捐川,例如將多個動畫鏈接到一起,這種方式會受到一定的限制逸尖。這時我們可以使用它的父類ObjectAnimator古沥。通過ObjectAnimator,我們可以設(shè)置監(jiān)聽器娇跟,從而在動畫開始和結(jié)束時得到相應(yīng)的通知岩齿;另外在動畫做增量更新時也可以得到通知。
以下兩個代碼顯示了如何使用ObjectAnimator來修改我們的Flipper動畫代碼:
res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/flip_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
</FrameLayout>

使用Objectanimator實現(xiàn)擲硬幣動畫

public class FlipperActivity extends Activity {

    private boolean mIsHeads;
    private ObjectAnimator mFlipper;
    private Bitmap mHeadsImage, mTailsImage;
    private ImageView mFlipImage;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mHeadsImage = BitmapFactory.decodeResource(getResources(), R.drawable.heads);
        mTailsImage = BitmapFactory.decodeResource(getResources(), R.drawable.tails);
        
        mFlipImage = (ImageView)findViewById(R.id.flip_image);
        mFlipImage.setImageBitmap(mHeadsImage);
        mIsHeads = true;
        
        mFlipper = ObjectAnimator.ofFloat(mFlipImage, "rotationY", 0f, 360f);
        mFlipper.setDuration(500);
        mFlipper.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (animation.getAnimatedFraction() >= 0.25f && mIsHeads) {
                    mFlipImage.setImageBitmap(mTailsImage);
                    mIsHeads = false;
                }
                if (animation.getAnimatedFraction() >= 0.75f && !mIsHeads) {
                    mFlipImage.setImageBitmap(mHeadsImage);
                    mIsHeads = true;
                }
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            mFlipper.start();
            return true;
        }
        return super.onTouchEvent(event);
    }
}

屬性動畫提供了一些之前舊動畫系統(tǒng)沒有的變換功能苞俘,例如x軸和y軸的旋轉(zhuǎn)效果盹沈,從而實現(xiàn)三維變換效果。本例中吃谣,我們不需要計算縮放比例來是實現(xiàn)旋轉(zhuǎn)乞封,只需要告訴視圖沿著y軸旋轉(zhuǎn)即可。正因為如此岗憋,我們不再需要使用兩個動畫來操作硬幣肃晚,整個旋轉(zhuǎn)過程只需要操作視圖的rotationY屬性即可。
另一個強大之處就是AnimationUpdateListener澜驮,它提供了動畫運行過程中的常規(guī)回調(diào)方法陷揪。getAnimationFraction()方法會返回當(dāng)前動畫完成的百分比惋鸥。還可以通過getAnimatedValue()得到當(dāng)前動畫某個屬性的準(zhǔn)確值杂穷。
本例中,我們使用第一個方法在動畫運行到兩個時刻(硬幣可以換面卦绣,即90°和270°或者動畫時長的25%和75%)時耐量,更換正反面的圖片。因為并不能保證從每個角度我們可以得到通知滤港,所有當(dāng)達(dá)到閾值后廊蜒,我們會立即更換圖片趴拧。我們還設(shè)置了一個布爾標(biāo)識來避免在旋轉(zhuǎn)過程中對同一個值進(jìn)行重復(fù)的圖片設(shè)置(這會產(chǎn)生不必要的性能損耗)。
如果應(yīng)用程序需要鏈接多個動畫山叮,ObjectAnimation還可以支持更加傳統(tǒng)的AnimationListener來響應(yīng)動畫的主要事件著榴,例如開始、結(jié)束和重復(fù)屁倔。
提示:
在Android4.4上脑又,Animation還支持pause()和resume()方法以掛起運行中的動畫而不用完全取消它。

2.AnimationSet

如果需要執(zhí)行多個動畫锐借,則可以在AnimationSet中聚集這些動畫问麸。可以同時播放AnimationSet中的所有動畫钞翔,或者依次播放每個動畫严卖。定義動畫集合的Java代碼可能稍微有些冗長,因此我們將在此例中改為使用XML動畫格式布轿。以下代碼定義了一組將應(yīng)用于硬幣翻轉(zhuǎn)的動畫哮笆。
res/animator/flip.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <!-- 建立硬幣旋轉(zhuǎn)的線性重復(fù) -->
    <objectAnimator
        android:propertyName="rotationX"
        android:duration="400"
        android:valueFrom="0"
        android:valueTo="360"
        android:valueType="floatType"
        android:repeatMode="restart"
        android:repeatCount="3"
        android:interpolator="@android:interpolator/linear"/>
    <!-- 增加一個提升動畫以顯示硬幣在空中上升 -->
    <objectAnimator
        android:propertyName="translationY"
        android:duration="800"
        android:valueTo="-200"
        android:valueType="floatType"
        android:repeatMode="reverse"
        android:repeatCount="1" />
</set>

此處我們在<set>中定義了兩個同時播放的動畫(通過android:ordering = "together")。第一個動畫我們前面以及看過汰扭,用于旋轉(zhuǎn)硬幣圖片一次疟呐。此動畫設(shè)置為重復(fù)3次,提供3個完整的旋轉(zhuǎn)东且。圖片的默認(rèn)插值器是加速/減速時間曲線启具,這看起來會結(jié)束硬幣翻轉(zhuǎn)動畫。為提供全程一致的速度珊泳,我們改為對動畫應(yīng)用系統(tǒng)的線性插值器鲁冯。
第二個動畫使硬幣在旋轉(zhuǎn)期間沿著視圖向上滑動,看起來就像是硬幣被扔到空中的效果色查。因為硬幣還必須落回來薯演,將此動畫設(shè)置為在完成后反向運行一次。
以下代碼顯示了附加到翻轉(zhuǎn)器Activity的新動畫秧了。
帶有XML版本的AnimatorSet的翻轉(zhuǎn)器動畫

public class FlipperActivity extends Activity {

    private boolean mIsHeads;
    private AnimatorSet mFlipper;
    private Bitmap mHeadsImage, mTailsImage;
    private ImageView mFlipImage;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mHeadsImage = BitmapFactory.decodeResource(getResources(), R.drawable.heads);
        mTailsImage = BitmapFactory.decodeResource(getResources(), R.drawable.tails);

        mFlipImage = (ImageView)findViewById(R.id.flip_image);
        mFlipImage.setImageResource(R.drawable.heads);
        mIsHeads = true;

        mFlipper = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.flip);
        mFlipper.setTarget(mFlipImage);

        ObjectAnimator flipAnimator = (ObjectAnimator) mFlipper.getChildAnimations().get(0);
        flipAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (animation.getAnimatedFraction() >= 0.25f && mIsHeads) {
                    mFlipImage.setImageBitmap(mTailsImage);
                    mIsHeads = false;
                }
                if (animation.getAnimatedFraction() >= 0.75f && !mIsHeads) {
                    mFlipImage.setImageBitmap(mHeadsImage);
                    mIsHeads = true;
                }
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            mFlipper.start();
            return true;
        }
        return super.onTouchEvent(event);
    }
}

在此例中跨扮,我們在XML中使用AnimatorInflater構(gòu)造AnimatorSet對象。產(chǎn)生的動畫必須通過setTarget()附加到適當(dāng)?shù)哪繕?biāo)視圖验毡,這是ObjectAnimator.ofFloat()隱式完成的工作衡创。我們?nèi)匀恍枰狝nimatorUpdateListener確定何時從頭部切換到尾部,但該偵聽器不能直接應(yīng)用于集合對象晶通。因此璃氢,我們必須使用getChildAnimations()查找集合內(nèi)的旋轉(zhuǎn)動畫,以便在適當(dāng)?shù)奈恢酶郊哟藗陕犉鳌?br> 運行此新的示例將產(chǎn)生更加真實的硬幣翻轉(zhuǎn)動畫狮辽。

提供drawable資源:

heads.png

tails.png

Demo下載地址:
1.4 動畫視圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末一也,一起剝皮案震驚了整個濱河市巢寡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌椰苟,老刑警劉巖抑月,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舆蝴,居然都是意外死亡爪幻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門须误,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挨稿,“玉大人,你說我怎么就攤上這事京痢∧谈剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵祭椰,是天一觀的道長臭家。 經(jīng)常有香客問我,道長方淤,這世上最難降的妖魔是什么钉赁? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮携茂,結(jié)果婚禮上你踩,老公的妹妹穿的比我還像新娘。我一直安慰自己讳苦,他們只是感情好带膜,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸳谜,像睡著了一般膝藕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咐扭,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天芭挽,我揣著相機與錄音,去河邊找鬼蝗肪。 笑死袜爪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的穗慕。 我是一名探鬼主播饿敲,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逛绵!你這毒婦竟也來了怀各?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤术浪,失蹤者是張志新(化名)和其女友劉穎瓢对,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胰苏,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡硕蛹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了硕并。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片法焰。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖倔毙,靈堂內(nèi)的尸體忽然破棺而出埃仪,到底是詐尸還是另有隱情,我是刑警寧澤陕赃,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布卵蛉,位于F島的核電站,受9級特大地震影響么库,放射性物質(zhì)發(fā)生泄漏傻丝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一诉儒、第九天 我趴在偏房一處隱蔽的房頂上張望葡缰。 院中可真熱鬧,春花似錦忱反、人聲如沸运准。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胁澳。三九已至,卻和暖如春米者,著一層夾襖步出監(jiān)牢的瞬間韭畸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工蔓搞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胰丁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓喂分,卻偏偏與公主長得像锦庸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒲祈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 【Android 動畫】 動畫分類補間動畫(Tween動畫)幀動畫(Frame 動畫)屬性動畫(Property ...
    Rtia閱讀 6,164評論 1 38
  • 1甘萧、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,982評論 3 119
  • 1 背景 不能只分析源碼呀萝嘁,分析的同時也要整理歸納基礎(chǔ)知識,剛好有人微博私信讓全面說說Android的動畫扬卷,所以今...
    未聞椛洺閱讀 2,711評論 0 10
  • 黑色的夜布滿了黑 欲望包裹的是誰 腦垂體無限滋生的空虛 又是在哪里酒后上頭 黑色的夜布滿了黑 誰家門口兩個紅燈籠 ...
    孫子曰閱讀 2,591評論 2 2
  • 渡船出港織白浪牙言, 綠島金輝送客行。 碧水茫茫天際匿怪得, 舒懷遠(yuǎn)眺任風(fēng)情咱枉。 2017.5.31
    野山雅歌閱讀 229評論 0 0