Android動畫總結(jié)——布局動畫、轉(zhuǎn)場動畫

之前一篇文章總結(jié)了View動畫茄厘、屬性動畫矮冬、幀動畫,這篇文章繼續(xù)總結(jié)布局動畫次哈、轉(zhuǎn)場動畫胎署。


一、布局動畫

布局動畫的作用于ViewGroup窑滞,執(zhí)行動畫效果的是內(nèi)部的子View琼牧。布局動畫在android中可以通過LayoutAnimationLayoutTransition來實現(xiàn)。

1.LayoutAnimation

LayoutAnimation實際上是一個View動畫哀卫,用來控制子View顯示時的動畫效果巨坊。可以通過Java代碼或者Xml文件來定義LayoutAnimation動畫聊训。

(1)通過Java代碼來定義LayoutAnimation

定義子View的顯示動畫layout_item_anim_set.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="300"
     android:interpolator="@android:anim/accelerate_interpolator"
     android:shareInterpolator="true">

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>
    <translate
        android:fromXDelta="500"
        android:toXDelta="0"/>
</set>

ListView為例抱究,給ListView設(shè)置item的顯示動畫:

private void setLayoutAnimation() {
    Animation animation = AnimationUtils.loadAnimation(this, R.anim.layout_item_anim_set);
    LayoutAnimationController controller = new LayoutAnimationController(animation);
    controller.setDelay(0.5f);
    controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
    mListView.setLayoutAnimation(controller);
}
(2)通過Xml代碼來定義LayoutAnimation:

layout_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/layout_item_anim_set"
    android:animationOrder="normal"
    android:delay="0.5">
</layoutAnimation>

ListView所在布局中調(diào)用:

<ListView
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="#f1f1f1"
    android:dividerHeight="1dp"
    android:layoutAnimation="@anim/layout_anim"
    android:listSelector="?android:attr/selectableItemBackground"/>

setDelay()方法以及android:delay屬性表示子View動畫顯示的延遲時間比例。比如動畫執(zhí)行時間是300ms带斑,延遲比例是0.5鼓寺,那么延遲時間就是150ms,在Listview中勋磕,第一個item在延遲150ms開始動畫后妈候,第二個在300ms后開始動畫,第三個在450ms后開始挂滓,以此類推苦银。
setOder()方法以及android:animationOrder表示動畫執(zhí)行的順序類型,共有三種:normal表示子View按順序顯示,reverse表示子View按逆序顯示幔虏,random表示子View隨機先后顯示纺念。

LayoutAnimation效果圖

2.LayoutTransition

LayoutTransition用于在ViewGroup中有子View添加、刪除想括、隱藏陷谱、顯示時所有子View動畫效果。LayoutTransition有5中動畫變化形式

LayoutTransition.APPEARING:子View添加到容器中時的動畫效果LayoutTransition.CHANGE_APPEARING:子View添加到容器中時瑟蜈,其他子View位置改變的動畫效果
LayoutTransition.DISAPPEARING:子View被移除時的動畫效果
LayoutTransition.CHANGE_DISAPPEARING:子View被移除時烟逊,其他子View的動畫效果
LayoutTransition.CHANGING:子View在容器中位置變化時其他子View的動畫效果

(1)使用默認(rèn)的動畫樣式

只需要在使用的LinearLayout、FrameLayout铺根、RelativeLayout等ViewGroup容器的布局文件中添加android:animateLayoutChanges="true"即可宪躯,系統(tǒng)會使用默認(rèn)的LayoutTransition來實現(xiàn)子View添加、刪除或變化是的動畫效果位迂。

默認(rèn)的LayoutTransition效果

(2)使用自定義動畫樣式
private void init() {
    mContainer = (LinearLayout) findViewById(R.id.container);
    setLayoutTransition();
}

private void setLayoutTransition() {
    LayoutTransition transition = new LayoutTransition();
    // 子View添加到mContainer時的動畫
    Animator appearAnim = ObjectAnimator
            .ofFloat(null, "rotationX", 90, 0)
            .setDuration(transition.getDuration(LayoutTransition.APPEARING));
    transition.setAnimator(LayoutTransition.APPEARING, appearAnim);
    // 子Veiw從mContainer中移除時的動畫
    Animator disappearAnim = ObjectAnimator
            .ofFloat(null, "rotationX", 0, 90)
            .setDuration(transition.getDuration(LayoutTransition.DISAPPEARING));
    transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnim);
    // 子Veiw添加到mContainer中時其他子View的動畫
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 0);
    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);
    PropertyValuesHolder pvhTranslationY = PropertyValuesHolder
            .ofFloat("translationX", 0, 150, 0);
    Animator changeAppearAnim = ObjectAnimator
            .ofPropertyValuesHolder(mContainer, pvhLeft, pvhTop, pvhTranslationY)
            .setDuration(transition.getDuration(LayoutTransition.CHANGE_APPEARING));
    transition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAppearAnim);
    // 子View從mContainer中移除時其他子View的動畫
    PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left", 0, 0);
    PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top", 0, 0);
    PropertyValuesHolder pvhTranslationYDis = PropertyValuesHolder
            .ofFloat("translationX", 0, -150, 0);
    ObjectAnimator changeDisAppearAnim = ObjectAnimator
            .ofPropertyValuesHolder(mContainer, outLeft, outTop, pvhTranslationYDis)
            .setDuration(transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
    transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeDisAppearAnim);

    mContainer.setLayoutTransition(transition);
}

// 添加子View到第0個位置
public void addData(View view) {
    View child = LayoutInflater.from(this)
            .inflate(R.layout.item, mContainer, false);
    mContainer.addView(child, 0);
}

// 移除第0個子View
public void deleteData(View view) {
    if (mContainer.getChildCount() != 0) mContainer.removeViewAt(0);
}

在使用PropertyValuesHolder時访雪,需要注意一下幾點:
1.LayoutTransition.CHANGE_APPEARINGLayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder構(gòu)造動畫才會有效果,其他任何方式構(gòu)造動畫都不會有效果囤官。
2.在使用PropertyValuesHolder時冬阳,”left””top”屬性就算不需要變化也必須要寫党饮,如果不需要變化可以寫成:

PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);

3.ofInt肝陪,ofFloat中的參數(shù)值,第一個值和最后一個值必須相同刑顺,不然此屬性所對應(yīng)的的動畫將被放棄氯窍,在此屬性值上將不會有效果:

PropertyValuesHolder pvhTranslationY = PropertyValuesHolder
            .ofFloat("translationX", 0, 150, 0);

4.使用的ofIntofFloat中蹲堂,如果所有參數(shù)值都相同狼讨,也將不會有動畫效果。

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);

動畫的參數(shù)全部相同柒竞,left這個屬性的動畫不會有任何效果政供。

說明:關(guān)于PropertyValuesHolder幾個注意點參考自文章animateLayoutChanges與LayoutTransition

自定義動畫樣式配置LayoutTransition效果


二朽基、轉(zhuǎn)場動畫

1.Android 5.0之前轉(zhuǎn)場動畫

在Android 5.0以前實現(xiàn)轉(zhuǎn)場動畫是通過補間動畫來實現(xiàn)布隔,通常是在Activity中是overridePendingTransition(int enterAnim, int exitAnim)方法。
enterAnimexitAnim兩個參數(shù)對應(yīng)的是兩個View動畫:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_anim);
    setStartActivityAnim();
}

private void setStartActivityAnim() {
    overridePendingTransition(R.anim.activity_right_in, R.anim.activity_left_out);
}

入場動畫activity_right_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromXDelta="100%p"
    android:toXDelta="0"/>

出場動畫activity_left_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromXDelta="0"
    android:toXDelta="-100%p"/>

ActivityonCreate中調(diào)用overridePendingTransition方法只對主動啟動Activity有效稼虎,如果我們返回上一個Activity也需要同樣的轉(zhuǎn)場動畫衅檀,就需要在finish方法也添加上這個方法。

@Override
public void finish() {
    super.finish();
    setEndActivityAnim();
}

private void setEndActivityAnim() {
    overridePendingTransition(R.anim.activity_left_in, R.anim.activity_right_out);
}

finish時入場動畫activity_left_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromXDelta="-100%p"
    android:toXDelta="0"/>

finish時出場動畫activity_right_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromXDelta="0"
    android:toXDelta="100%p"/>

Android 5.0前轉(zhuǎn)場動畫效果
2.Android 5.0之后轉(zhuǎn)場動畫 Activity Transition

Android 5.0之后霎俩,谷歌引入了 Activity Transition 來實現(xiàn)交互更加友好的轉(zhuǎn)場動畫效果哀军。

Tansition的類型共有三種:
進(jìn)入 —— 決定Activity中的所有視圖怎么進(jìn)入屏幕
退出 —— 決定Activity中的所有視圖怎么退出屏幕
共享元素 —— 決定兩個Activity之間的過渡時怎么共享它們的視圖

進(jìn)入和退出包含如下動畫效果:
explode(分解) —— 從屏幕中間進(jìn)或出
slide(滑動) —— 從屏幕邊緣進(jìn)或出地
fade(淡出) —— 改變屏幕上視圖的不透明度實現(xiàn)添加或移除視圖的效果

共享元素包含如下動畫效果:
changeBounds —— 改變目標(biāo)視圖的布局邊界
changeClipBounds —— 裁剪目標(biāo)視圖邊界
changeTransform —— 改變目標(biāo)視圖的縮放比例和旋轉(zhuǎn)角度
changeImageTransform —— 改變目標(biāo)圖片的大小和縮放比例

說明:Tansition分類及動畫效果說明參考《Android群英傳》

先來看下Explode(分解)沉眶、Slide(滑動)、Fade(淡出)三種轉(zhuǎn)場動畫的使用杉适。

第一個Activity中:

public void explode(View view) {
    Intent intent = new Intent(this, NextTransitionActivity.class);
    intent.putExtra("flag", "explode");
    startActivity(intent,
            ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle());
}

public void slide(View view) {
    Intent intent = new Intent(this, NextTransitionActivity.class);
    intent.putExtra("flag", "slide");
    startActivity(intent,
            ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle());
}

public void fade(View view) {
    Intent intent = new Intent(this, NextTransitionActivity.class);
    intent.putExtra("flag", "fade");
    startActivity(intent,
            ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle());
}

啟動的第二個Activity中:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    switch (getIntent().getStringExtra("flag")) {
        case "explode":
            getWindow().setEnterTransition(new Explode());
            getWindow().setExitTransition(new Explode());
            break;
        case "slide":
            getWindow().setEnterTransition(new Slide());
            getWindow().setExitTransition(new Slide());
            break;
        case "fade":
            getWindow().setEnterTransition(new Fade());
            getWindow().setExitTransition(new Fade());
            break;
    }
    setContentView(R.layout.activity_next_transition);
}

在第二個Activity中可以通過在style中配置<item name="android:windowContentTransitions">true</item>
就不需要調(diào)用getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)谎倔。


共享元素轉(zhuǎn)場動畫,使用也比較簡單:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    TransitionAdapter.TransitionViewHolder holder = (TransitionAdapter.TransitionViewHolder) view.getTag();
    View shareViewImg = holder.civImg;
    View shareViewName = holder.tvName;
    Intent intent = new Intent(this, NextTransitionActivity.class);
    intent.putExtra("flag", "share");
    startActivity(intent, ActivityOptionsCompat
            .makeSceneTransitionAnimation(this,
                    Pair.create(shareViewImg, "shareView_img"),
                    Pair.create(shareViewName, "shareView_name"))
            .toBundle());
}

這里使用ListView實現(xiàn)一個列表淘衙,列表中的頭像和名字作為共享元素传藏。在ListViewitem的布局以及第二個啟動的Activity的布局中,被共享的View都需要在布局文件中添加上相同android:transitionName屬性彤守,當(dāng)然也可以在Java代碼中通過ViewCompat.setTransitionName(View view, String transitionName)方法來設(shè)置共享ViewtransitionName
我們給頭像和名稱分別指定android:transitionName="shareView_img"android:transitionName="shareView_name"哭靖。
點擊item后啟動目標(biāo)Activity時具垫,指定的options參數(shù)為:

ActivityOptionsCompat.makeSceneTransitionAnimation(this,
        Pair.create(shareViewImg,"shareView_img"),
        Pair.create(shareViewName, "shareView_name"))
.toBundle());

通過options參數(shù),可以利用Pair構(gòu)造多個共享元素试幽,但是共享元素View的共享名稱transitionName必須一一對應(yīng)筝蚕。

共享元素轉(zhuǎn)場動畫效果


源碼:https://github.com/xiaoyanger0825/AnimationSummary

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铺坞,隨后出現(xiàn)的幾起案子起宽,更是在濱河造成了極大的恐慌页屠,老刑警劉巖茬底,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異扛芽,居然都是意外死亡擒滑,警方通過查閱死者的電腦和手機腐晾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丐一,“玉大人藻糖,你說我怎么就攤上這事】獬担” “怎么了巨柒?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柠衍。 經(jīng)常有香客問我洋满,道長,這世上最難降的妖魔是什么拧略? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任芦岂,我火速辦了婚禮,結(jié)果婚禮上垫蛆,老公的妹妹穿的比我還像新娘禽最。我一直安慰自己腺怯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布川无。 她就那樣靜靜地躺著呛占,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懦趋。 梳的紋絲不亂的頭發(fā)上晾虑,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音仅叫,去河邊找鬼帜篇。 笑死,一個胖子當(dāng)著我的面吹牛诫咱,可吹牛的內(nèi)容都是我干的笙隙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼坎缭,長吁一口氣:“原來是場噩夢啊……” “哼竟痰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掏呼,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤坏快,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后憎夷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體莽鸿,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年岭接,在試婚紗的時候發(fā)現(xiàn)自己被綠了富拗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸣戴,死狀恐怖啃沪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窄锅,我是刑警寧澤创千,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站入偷,受9級特大地震影響追驴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疏之,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一殿雪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锋爪,春花似錦丙曙、人聲如沸爸业。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扯旷。三九已至,卻和暖如春索抓,著一層夾襖步出監(jiān)牢的瞬間钧忽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工逼肯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留耸黑,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓篮幢,卻偏偏與公主長得像崎坊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子洲拇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,510評論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,708評論 22 664
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件曲尸、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,024評論 4 62
  • 六一兒童節(jié)快樂赋续,希望身邊的人都能擁有一顆兒童之心,保持點兒童般的純真和快樂另患,或許我們的生活會有不同的變化纽乱。 所為人...
    開拓者2021閱讀 273評論 0 0
  • 夜色深如海鸦列,寒氣疾若潮。 惱人秋風(fēng)逐花凋鹏倘。 香冷高樓無緒薯嗤, 詩吟度殘宵。 試墨遠(yuǎn)箋瘦纤泵, 憑欄嘆夢遙骆姐。 鬢絲依舊為誰...
    逸塵居士閱讀 197評論 0 0