之前一篇文章總結(jié)了View動畫茄厘、屬性動畫矮冬、幀動畫,這篇文章繼續(xù)總結(jié)布局動畫次哈、轉(zhuǎn)場動畫胎署。
一、布局動畫
布局動畫的作用于ViewGroup
窑滞,執(zhí)行動畫效果的是內(nèi)部的子View琼牧。布局動畫在android中可以通過LayoutAnimation
或LayoutTransition
來實現(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隨機先后顯示纺念。
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添加、刪除或變化是的動畫效果位迂。
(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_APPEARING
和LayoutTransition.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.使用的ofInt
,ofFloat
中蹲堂,如果所有參數(shù)值都相同狼讨,也將不會有動畫效果。
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);
動畫的參數(shù)全部相同柒竞,left這個屬性的動畫不會有任何效果政供。
說明:關(guān)于PropertyValuesHolder
幾個注意點參考自文章animateLayoutChanges與LayoutTransition。
二朽基、轉(zhuǎn)場動畫
1.Android 5.0之前轉(zhuǎn)場動畫
在Android 5.0以前實現(xiàn)轉(zhuǎn)場動畫是通過補間動畫來實現(xiàn)布隔,通常是在Activity
中是overridePendingTransition(int enterAnim, int exitAnim)
方法。
enterAnim
和exitAnim
兩個參數(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"/>
在Activity
的onCreate
中調(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"/>
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)一個列表淘衙,列表中的頭像和名字作為共享元素传藏。在ListView
的item
的布局以及第二個啟動的Activity
的布局中,被共享的View
都需要在布局文件中添加上相同android:transitionName
屬性彤守,當(dāng)然也可以在Java代碼中通過ViewCompat.setTransitionName(View view, String transitionName)
方法來設(shè)置共享View
的transitionName
。
我們給頭像和名稱分別指定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)筝蚕。