概述
當(dāng)你想要從一個(gè)頁(yè)面A轉(zhuǎn)換到頁(yè)面B共郭,而且他們共享一個(gè)元素(比如是一個(gè)view)胆胰,在這種場(chǎng)景下感昼,最好的用戶體驗(yàn)可能就是將共享的元素直接變換到最終的地方和大小坛悉,這會(huì)使用戶專(zhuān)注于應(yīng)用而且有一種連貫性的表達(dá)荷憋。這在Android5.0以上是可以很方便的實(shí)現(xiàn)的台颠,接下來(lái)就說(shuō)說(shuō)不同場(chǎng)景下ShareElements的使用。
Fragment/Activity跳轉(zhuǎn)到Activity
跳轉(zhuǎn)Activity相對(duì)簡(jiǎn)單一些勒庄,官方封裝好了使用方法:
//這是ContextCompat里的方法串前,參數(shù)中多了一個(gè)bundle,可配置共享元素相關(guān)設(shè)置
public static void startActivity(@NonNull Context context, @NonNull Intent intent,
@Nullable Bundle options) {
if (Build.VERSION.SDK_INT >= 16) {
context.startActivity(intent, options);
} else {
context.startActivity(intent);
}
}
//這是ActivityOptionsCompat里的方法实蔽,方便我們直接生成對(duì)應(yīng)的bundle
@NonNull
public static ActivityOptionsCompat makeSceneTransitionAnimation(@NonNull Activity activity,
@NonNull View sharedElement, @NonNull String sharedElementName) {
if (Build.VERSION.SDK_INT >= 21) {
return createImpl(ActivityOptions.makeSceneTransitionAnimation(
activity, sharedElement, sharedElementName));
}
return new ActivityOptionsCompat();
}
//如果傳遞多個(gè)共享元素荡碾,則要使用到Pair
public static ActivityOptionsCompat makeSceneTransitionAnimation(@NonNull Activity activity,
Pair<View, String>... sharedElements)
看完support包提供的方法,來(lái)看具體使用吧:
Intent intent = new Intent(getContext(), ImageViewActivity.class);
ActivityCompat.startActivity(getContext(), intent,
ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(), ivUserInfoHead, ViewCompat.getTransitionName(ivUserInfoHead)).toBundle());
注意點(diǎn):
- 基本要求局装,轉(zhuǎn)場(chǎng)涉及的兩個(gè)Fragment的共享元素的transitionName要一致坛吁,可以在xml中設(shè)置,也可以通過(guò)ViewCompat.setTransitionName(view, "name")在代碼中設(shè)置铐尚。
- 如果使用了自定義按鈕返回拨脉,非系統(tǒng)返回,則結(jié)束Activity時(shí)不能直接finish()宣增,需要使用supportFinishAfterTransition()替代玫膀,這樣返回也會(huì)有相應(yīng)的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)了。
Fragment跳轉(zhuǎn)到Fragment
直接上代碼:
//首先在Fragment中加載一個(gè)小圖標(biāo)Fragment
getChildFragmentManager().beginTransaction()
.replace(R.id.view_holder, new ImageViewSmallFragment())
.commit();
//小圖標(biāo)Fragment中監(jiān)聽(tīng)點(diǎn)擊事件跳轉(zhuǎn)到大圖標(biāo)Fragment
view.findViewById(R.id.test_img).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ImageViewFragment newFragment = new ImageViewFragment();
//注意:這里要設(shè)置共享元素的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)爹脾,也可以把這段代碼放在newFragment的onCreate里面帖旨,看個(gè)人喜歡,我更傾向于放跳轉(zhuǎn)這里灵妨,這樣轉(zhuǎn)場(chǎng)的邏輯在一個(gè)地方碉就,更方便閱讀和理解
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
newFragment.setSharedElementEnterTransition(
TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
}
//注意:這里要用getFragmentManager(),因?yàn)橐鎿Q掉自己
getFragmentManager().beginTransaction()
//設(shè)置指定的共享元素和共享元素名字
.addSharedElement(view, ViewCompat.getTransitionName(view))
//注意:這里只能用replace闷串,用add無(wú)效
.replace(R.id.view_holder, newFragment)
//注意:這里要壓棧瓮钥,返回時(shí)才能也有轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
.addToBackStack("")
.commit();
}
});
//新Fragment中返回時(shí)使用popBackStack方法回退,這樣返回也能有相應(yīng)的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)了烹吵,注意碉熄,這里要使用getFragmentManager()
getFragmentManager().popBackStack();
注意點(diǎn):
- 基本要求,轉(zhuǎn)場(chǎng)涉及的兩個(gè)Fragment的共享元素的transitionName要一致肋拔,可以在xml中設(shè)置锈津,也可以通過(guò)ViewCompat.setTransitionName(view, "name")在代碼中設(shè)置。
- 跳轉(zhuǎn)新Fragment只能使用replace凉蜂,使用add無(wú)效琼梆,因?yàn)閞eplace會(huì)觸發(fā)原來(lái)Fragment生命周期的onPause性誉,而add不會(huì),所以使用add無(wú)法觸發(fā)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)茎杂。
- 既然只能使用replace错览,則表示跳轉(zhuǎn)的Fragment和原來(lái)的Fragment要在同一個(gè)布局容器里,否則也是不會(huì)觸發(fā)原來(lái)Fragment的onPause的煌往。
- 是在同一個(gè)布局容器里倾哺,說(shuō)明兩個(gè)Fragment是同級(jí)的,在舊Fragment中點(diǎn)擊跳轉(zhuǎn)新Fragment時(shí)刽脖,不能使用getChildFragmentManager羞海,在Activity中就使用getSupportFragmentManager,如果是Fragment里則使用getFragmentManager()曲管。
- 新Fragment需要設(shè)置指定的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)却邓。
- 跳轉(zhuǎn)時(shí)要添加addToBackStack,這樣返回時(shí)才能正常pop院水,pop要使用getFragmentManager()申尤,返回才能有轉(zhuǎn)場(chǎng)動(dòng)畫(huà)效果。
- 要使用27.0.0以上的support包衙耕,因?yàn)樾碌膕upport轉(zhuǎn)場(chǎng)動(dòng)畫(huà)使用的是support包里的transition昧穿,可以參考官方support的releaseNote描述:Fragment can use support library versions of Transition for fragment transitions, including shared-element transitions.
共享元素延時(shí)加載情況
經(jīng)常會(huì)有如下場(chǎng)景,下一個(gè)頁(yè)面的共享元素需要等網(wǎng)絡(luò)接口返回后才能確定具體的位置和大小橙喘,這樣才能完成轉(zhuǎn)場(chǎng)動(dòng)畫(huà)时鸵,此時(shí),就不能直接執(zhí)行轉(zhuǎn)場(chǎng)厅瞎,需要做一些處理:
//首先在onCreate方法里暫停轉(zhuǎn)場(chǎng)
supportPostponeEnterTransition();
//然后在布局完成后饰潜,也就是合適的時(shí)機(jī)恢復(fù)轉(zhuǎn)場(chǎng)
supportStartPostponedEnterTransition();
總結(jié)
在適當(dāng)場(chǎng)景下添加轉(zhuǎn)場(chǎng)動(dòng)畫(huà),可以提高用戶體驗(yàn)和簸。但不要在一個(gè)轉(zhuǎn)場(chǎng)里添加過(guò)多的共享元素彭雾,這樣反面影響了用戶的注意點(diǎn),感覺(jué)亂锁保。官方提供的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)薯酝,快點(diǎn)用到項(xiàng)目里吧~