1. Activity共享元素跳轉概述
顯然铅协,兩個Activity之間有相同元素。
2. 實現(xiàn)Activity共享元素跳轉過程
A跳轉到B,實現(xiàn)共享元素轉場動畫只需以下幾步:
2.1 res/transition文件夾,定義界面或共享元素的轉場動畫
請看 : 三摊沉、定義 界面指定元素 或界面間共享元素 的轉場動畫基礎
2.2 在 每個 Activity 指定轉場動畫的 style ,并在Manifest 文件中 設置對應的 theme狐史。
注意,Activity Transition API 也可以使用 setSharedElementExitTransition() 和setSharedElementReenterTransition()方法分別設置共享元素的exit 和reenter 變換说墨。但是一般來講這是不必要的骏全。如果你想看先關的例子,可以查看這篇博客
this blog post ; 至于為什么Fragment中沒有共享元素的exit 和reenter 變換尼斧,請查看George Mount在stackoverflow上的回答:this StackOverflow post 姜贡。
<style name="AppTheme.ShareElementTransition">
<!-- 1. 開啟過渡效果,一定要-->
<item name="android:windowContentTransitions">true</item>
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowSharedElementEnterTransition">@transition/search_shared_enter</item>
<item name="android:windowSharedElementReturnTransition">@transition/search_shared_return</item>
<item name="android:windowSharedElementsUseOverlay">true</item>
</style>
2.3 在activity B中,為需要共享的元素設置transitionName(轉場動畫中的targetId的view)
a -> b
//activity_a.xml
//這里的View可以不設置 : android:transitionName="@string/transition_search_back"
<ImageButton
android:id="@+id/searchback"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/ic_arrow_back_padded"
/>
--------------------------------------------------------------------------------------------------
//activity_b.xml ,是不是同一個view呢?還是只是Id一樣?
//回答 : 不是同一個View,id可以不一樣,因為共享只是設置動畫效果
<ImageButton
android:id="@+id/a"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/ic_arrow_back_padded"
android:transitionName="@string/transition_search_back" />
//或者
ViewCompat.setTransitionName(view,"imageView");
2.4 啟動Activity b
ActivityOptionsCompat options=ActivityOptionsCompat.makeSceneTransitionAnimation(this,view,transitionName);
ActivityCompat.startActivity(this, intent, options.toBundle());
2.5 在B中設置共享元素動畫
上面四個步驟就可以實現(xiàn)共享的動畫效果,但是!!!
Transitions并沒有把之前的View傳遞過去,本質上是兩個不同的對象,所以需要在ActivityB中為共享元素賦值棺棵÷タ龋可以在
startActivity
把數(shù)據(jù)通過intent
或Bundle
的形式傳遞,然后在ActivityB中讀取數(shù)據(jù)進行賦值....或者直接為共享的View 設置一個死值
3. 深入分析
framework的共享元素變換是通過運行時改變其屬性實現(xiàn)的,當Activity A 調用 Activity B 烛恤,發(fā)生的事件流如下:
1. Activity A調用startActivity()母怜, Activity B被創(chuàng)建,測量缚柏,同時初始化為半透明的窗口和透明的背景顏色苹熏。
2. framework重新分配每個共享元素在B中的位置與大小,使其跟A中一模一樣。之后柜裸,B的進入變換(enter transition)捕獲到共享元素在B中的初始狀態(tài)缕陕。
3. framework重新分配每個共享元素在B中的位置與大小粱锐,使其跟B中的最終狀態(tài)一致疙挺。之后,B的進入變換(enter transition)捕獲到共享元素在B中的結束狀態(tài)怜浅。
4. B的進入變換(enter transition)比較共享元素的初始和結束狀態(tài)铐然,同時基于前后狀態(tài)的區(qū)別創(chuàng)建一個Animator(屬性動畫對象)。
5. framework 命令A隱藏其共享元素恶座,動畫開始運行搀暑。隨著動畫的進行,framework 逐漸將B的activity窗口顯示出來跨琳,當動畫完成自点,B的窗口才完全可見。
與內容變換(content transition)取決于view的可見性不同(visibility)怎诫,共享元素變換取決于每個共享元素的位置酣胀、大小以及外觀赡矢。
共享元素變換并不是真正實現(xiàn)了兩個activity或者Fragment之間元素的共享,實際上我們看到的幾乎所有變換效果中(不管是B進入還是B返回A),共享元素都是在B中繪制出來的术唬。Framework沒有真正試圖將A中的某個元素傳遞給B,而是采用了不同的方法來達到相同的視覺效果滚澜。A傳遞給B的是共享元素的狀態(tài)信息粗仓。B利用這些信息來初始化共享View元素,讓它們的位置设捐、大小借浊、外觀與在A中的時候完全一致。當變換開始的時候萝招,B中除了共享元素之外蚂斤,所有的其他元素都是不可見的。隨著動畫的進行即寒,framework 逐漸將B的activity窗口顯示出來橡淆,當動畫完成,B的窗口才完全可見母赵。
3.1 監(jiān)聽動畫的變化過程,做出相對應的操作
//當然也可以監(jiān)聽 Return,Exit,Reenter時的動畫
getWindow().getSharedElementEnterTransition().addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
4. 實戰(zhàn)例子
//AndroidManifest.xml
<activity
android:name=".ShareElementsToActActivity"
android:label="ShareElementsToAct"
android:theme="@style/AppTheme.ShareElementsToAct" />
//style.xml
<style name="AppTheme.ShareElementsToAct">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowSharedElementEnterTransition">@transition/enter_share_transitions</item>
<item name="android:windowSharedElementReturnTransition">@null</item> <!--默認和enter相反-->
</style>
enter_share_transitions.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:interpolator="@android:interpolator/decelerate_cubic">
<changeBounds>
<!--patternPathMotion android:patternPathData="M0 0 L0 100 L100 0"/-->
<targets>
<target android:targetId="@id/iv"/>
<target android:targetId="@id/tv"/>
</targets>
<!-- <arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="90"
android:minimumVerticalAngle="0" />-->
</changeBounds>
</transitionSet>
activity_share_elements_to_act.xml,注意transitionName分別為shareIvToAct
和shareTvToAct
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gdut.dkmfromcg.transitionlearn.ShareElementsToActActivity">
<ImageView
android:id="@+id/iv"
android:src="@drawable/bangtang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:transitionName="shareIvToAct"/>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/iv"
android:textSize="24dp"
android:layout_centerHorizontal="true"
android:transitionName="shareTvToAct"/>
</RelativeLayout>
transitionName也是為shareIvToAct 和shareTvToAct
shareAct=findViewById(R.id.shareBetweenAct);
shareAct.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(activity,ShareElementsToActActivity.class);
ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
new Pair<View, String>(ivShareToAct,"shareIvToAct"),
new Pair<View, String>(tvShareToAct,"shareTvToAct"));
Bundle bundle=optionsCompat.toBundle();
/**
* 共享的數(shù)據(jù)仍需從這邊傳遞
*/
//imageView 轉換成Bitmap,可以進行傳遞,但是:Activity之間傳遞的數(shù)據(jù)量不能過大,否則程序會ORM.事實證明確實ORM了
Bitmap bitmap=((BitmapDrawable)ivShareToAct.getDrawable()).getBitmap();
//bundle.putParcelable("key_share_iv",bitmap); 所以這里不傳遞Bitmap
bundle.putCharSequence("key_share_tv",tvShareToAct.getText());
intent.putExtra("key_bundle",bundle);
//startActivity(intent); 這樣不會產(chǎn)生共享元素的效果
ActivityCompat.startActivity(activity,intent,bundle);
}
});
ShareElementsToActActivity
public class ShareElementsToActActivity extends AppCompatActivity {
private static final String TAG = "ShareElementsToActActiv";
ImageView imageView;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_elements_to_act);
imageView=findViewById(R.id.iv);
textView=findViewById(R.id.tv);
Intent intent=getIntent();
Bundle bundle=intent.getBundleExtra("key_bundle");
Log.d(TAG, ": "+bundle);
if (bundle!=null){
//imageView.setImageBitmap((Bitmap) bundle.getParcelable("key_share_iv"));
textView.setText(bundle.getCharSequence("key_share_tv"));
}
}
}
例子源碼:animatedTransitionsLearn-master
Transition系列文章
一逸爵、初識Transition—實現(xiàn)兩個場景的變換
二、番外篇 Transition之ViewOverlay
三凹嘲、定義 界面指定元素 或界面間共享元素 的轉場動畫基礎
四师倔、Content Transition實現(xiàn)非共享元素轉場
五、SharedElementTransition之Activity間的轉場
六周蹭、SharedElementTransition之Fragment間的轉場
七趋艘、番外篇- 自定義Visibility
八疲恢、5.0以下實現(xiàn)共享轉場
本篇參考:
深入理解共享元素變換(Shared Element Transition)-上
animatedTransitionsLearn-master
Android Transition Framework詳解---超炫的動畫框架