Jetpack是google近年來力推的一系列安卓開發組件框架,目前仍在不斷的更新與完善,其主要目的是幫助開發者們構建高質量的現代化APP,減少模版代碼。
本系列文章將會介紹Jetpack常用組件框架的使用方式,如Navigation、ViewModel、LiveData、Room、Paging、WorkManager等。
一、Navigation簡介
Navigation主要用于實現Fragment代替Activity的頁面導航功能,讓Fragment能夠輕松的實現跳轉與傳遞參數,我們可以通過使用Navigation,讓Fragment代替android項目中絕大多數的Activity。
本文主要內容有:Navigation依賴、創建第一個Navigation頁面、Navigation頁面跳轉、Navigation頁面攜帶參數跳轉、Navigation頁面數據回傳、配置ActionBar、切換動畫、共享元素動畫
我以前在開發android項目時,除了少部分的內嵌頁面使用Fragment之外,其他絕大多數的頁面都是使用Activity來實現,因為安卓為Activity提供了一套完整的頁面解決方案:
- oneActivity跳轉并傳遞參數到twoActivity:
Intent intent = new Intent(context,twoActivity.class);
intent.putExtra(key,value);//傳遞參數
//oneActivity.startActivity(intent);//無回傳參數
oneActivity.startActivityForResult(intent,oneRequestCode);
- 在twoActivity獲取參數:
value = getIntent().getStringExtra(key);
- 在twoActivity回傳參數到oneActivity:
Intent intent = getIntent();
intent.putExtra(key,value);//回傳參數
setResult(RESULT_OK,intent);
finish();
- 在oneActivity接收回傳的參數
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
if (requestCode == oneRequestCode){
value = data.getStringExtra(key);
}
}
}
毫無疑問,Activity可以說是我們android開發人員最熟悉的組件了,而且功能也非常成熟與完善,既然如此,google為何又要開發出一套全新的Navigation框架呢?原因我認為主要有兩個:
- Activity太過于重量級了,如果我們去查看Activity的源碼就會發現,其內部實現機制卻是非常復雜的,因此每一個Activity的啟動會消耗大量的資源,增加了開發高質量android項目的難度。相比之下,Fragment顯得非常的輕量級。
- 頁面是APP中最重要的組件,使用Activity構建頁面卻往往需要維護大量復雜的生命周期,無疑增加了android項目開發的難度,對于想要學習android開發的人來說更是不友好,在開發技術日新月異的今天,如此以往不利于android生態的發展,所以google需要一個能夠在絕大多數場景代替Activity、簡單且現代化的頁面解決方案。
二、Navigation的使用
(一)新建項目
- 依次點擊File -- New -- NewProject
- 選擇Empty Activity,點擊Next
- 輸入項目名和包名,點擊Finish完成新建項目。
我們將在這個Project上學習Navigation的使用。
(二)添加依賴
- 打開Module:app的build.gradle,在dependencies中添加依賴:
dependencies {
def nav_version = "2.1.0"
// Java
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
- 使用Safe Args Gradle插件,實現在Navigation頁面間類型安全的傳遞數據(如果不使用Safe Args可以跳過這一步)。先打開Project的build.gradle添加以下內容:
buildscript {
...
dependencies {
...
def nav_version = "2.1.0"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
然后再打開Module:app的build.gradle添加以下內容:
apply plugin: "androidx.navigation.safeargs"
這樣子我們就完成Navigation依賴的添加了。
(三)創建第一個Navigation頁面
Navigation由3個關鍵部分組成:
- 導航圖:用于配置導航頁面及路徑的XML文件
- NavHost:用于顯示導航圖中目標頁面的空白容器,常用NavHostFragment來實現
- NavController:負責在 NavHost 中管理頁面導航的對象,但需要頁面跳轉時,NavController會控制NavHost中的目標頁面進行交換
1. 創建導航圖
我們先來創建一個導航圖,在項目上右鍵選擇New - Android Resource File,在彈出窗口中選擇Resource Type為Navigation(如下圖),接著為導航圖命名(例如nav_main),最后點擊OK創建好的導航圖會保存在res/navigation/nav_main.xm,接下來我們雙擊打開創建好的導航圖(如下圖)
里面還沒有任何頁面,所以我們先來創建一個頁面,首先創建一個布局文件(例如fragment_one.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">
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Hello Navigation"/>
</LinearLayout>
再創建一個Fragment(例如FragmentOne.java)
public class FragmentOne extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
接下來我們回到導航圖,把創建好的頁面添加到導航圖中,先雙擊導航圖界面上的New Destination小圖標,然后點擊我們創建好的頁面,即可完成頁面的添加(如下圖)
2. 創建NavHost
NavHost是用于顯示導航圖中目標頁面的空白容器,常用NavHostFragment來實現。這一步我們直接打開項目默認創建好的activity_main.xml,把NavHostFragment添加到里面即可:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:background="@color/colorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
app:popupTheme="@style/Theme.MaterialComponents.Light" />
<fragment
android:id="@+id/navHost"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
這一步做完之后,我們便完成了第一個Navigation頁面的創建,我們可以安裝到設備來看一下效果(如下圖):
(四)Navigation頁面跳轉
上文說到Navigation有3個關鍵部分,并且學習了其中的導航圖和NavHost,這一節我們來學習剩下的最后一個關鍵部分NavController,并實現Navigation頁面跳轉。
為了實現跳轉,我們需要創建第二個頁面,首先創建一個布局文件(例如fragment_two.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">
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="第二個頁面"/>
</LinearLayout>
再創建一個Fragment(例如FragmentTwo.java)
public class FragmentTwo extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_two, container, false);
}
}
接下來我們回到導航圖,把創建好的第二個頁面也添加到導航圖中,添加完成后如下圖:
接下來我們單擊選中第一個頁面(fragmentOne),可以看到選中后會出現藍色邊框和一個圓點(如下圖)
我們把鼠標移動到圓點上,按下鼠標把圓點拖動到第二個頁面上(fragmentTwo),我們可以看到系統生成了一條由fragmentOne指向fragmentTwo的箭頭,它代表了Navigation頁面切換的路徑。
緊接著,我們來修改第一個頁面fragment_one.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">
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Hello Navigation"/>
<Button
android:id="@+id/btnGoTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="跳轉到第二個頁面" />
</LinearLayout>
準備工作基本完成。
接下來,我們要依次點擊Build - Make Project,讓android studio先自動生成路徑的相關代碼。
最后便是實現跳轉的代碼,要實現Navigation頁面跳轉,我們首先獲取NavController:
NavController navController = Navigation.findNavController(getView());
然后再通過Navigation自動生成的FragmentOneDirections(自動生成的命名格式為:頁面名+Directions)獲取剛剛設置好的路徑:
NavDirections navDirections = FragmentOneDirections.actionFragmentOneToFragmentTwo();
最后通過NavController使用路徑進行跳轉即可:
navController.navigate(navDirections);
我們打開FragmentOne.java,把上述內容修改到里面,完整代碼如下:
public class FragmentOne extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_one, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button btnGoTwo = getView().findViewById(R.id.btnGoTwo);
btnGoTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 核心代碼
NavDirections navDirections = FragmentOneDirections.actionFragmentOneToFragmentTwo();
NavController navController = Navigation.findNavController(getView());
navController.navigate(navDirections);
}
});
}
}
這一步做完之后,我們便完成了Navigation頁面的跳轉,我們可以安裝到設備來看一下效果:
(五)Navigation頁面攜帶參數跳轉
上文我們完成了Navigation的跳轉,接下來我們看看如何攜帶參數進行跳轉。
場景:假設我們的fragmentTwo現在需要一個String類型的傳入參數Message,fragmentOne在跳轉時需要攜帶它。
首先我們打開導航圖,點擊fragmentTwo,在右邊找到Arguments這一行,點擊這一行右邊的“+”號(如下圖)
系統會彈出一個Add Argument Link的窗體,我們在這個窗體上添加傳入參數的信息。窗體的字段包括:
Name(參數名)
Type(參數類型)
Array(參數是否為列表)
Nullable(參數是否可為空)
Default Value(參數的默認值)
我們按照需求,添加一個String類型的傳入參數Message,然后點擊Add按鈕(如下圖)
接下來,我們依次點擊Build - Make Project,讓android studio自動生成參數的相關代碼。
緊接著,我們打開FragmentOne.java,修改代碼實現攜帶參數跳轉:
NavDirections navDirections = FragmentOneDirections.actionFragmentOneToFragmentTwo("你好,我是fragmentOne發來的消息");
NavController navController = Navigation.findNavController(getView());
navController.navigate(navDirections);
最后,我們回到FragmentTwo.java,利用Navigation自動生成的FragmentTwoArgs(自動生成的命名格式為:頁面名+Args)來獲取傳入的參數Message:
String message = FragmentTwoArgs.fromBundle(getArguments()).getMessage();
FragmentTwo.java的完整代碼如下:
public class FragmentTwo extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_two, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView tvMessage = getView().findViewById(R.id.tvMessage);
String message = FragmentTwoArgs.fromBundle(getArguments()).getMessage();
tvMessage.setText(message);
}
}
這一步做完之后,我們便完成了Navigation頁面攜帶參數跳轉,我們可以安裝到設備來看一下效果:
(六)Navigation頁面數據回傳
在本文最上面介紹Activity的時候,我們知道Activity能夠通過setResult實現數據的回傳,那么Navigation如何實現回傳呢?
目前google官方并沒有在Navigation框架本身實現該功能,而是建議開發者使用LiveData來實現這一功能,因此這一官方建議的解決方案我們會留到后面介紹LiveData時再進行介紹。
現階段我們可以采用另外一種簡單的方式來實現,首先我們知道,當前項目Navigation兩個頁面都運行在同一個Activity(MainActivity)中,而且在兩個頁面均可以通過getActivity訪問到,因此我們可以通過MainActivity來保存回傳的數據,實現簡單的數據回傳。
首先,在MainActivity.java添加以下內容:
private String navigationResultData;
public void setNavigationResultData(String navigationResultData){
this.navigationResultData = navigationResultData;
}
public String getNavigationResultData(){
return navigationResultData;
}
然后,在fragment_two.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">
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="第二個頁面"/>
<Button
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="返回" />
</LinearLayout>
在FragmentTwo.java對返回按鈕進行注冊監聽,點擊時關閉當前頁面并回傳參數:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView tvMessage = getView().findViewById(R.id.tvMessage);
String message = FragmentTwoArgs.fromBundle(getArguments()).getMessage();
tvMessage.setText(message);
// 對返回按鈕進行注冊監聽,點擊時關閉當前頁面并回傳參數
Button btnBack = getView().findViewById(R.id.btnBack);
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getActivity() instanceof MainActivity){
((MainActivity)getActivity()).setNavigationResultData("你好,我是FragmentTwo回傳的數據");
}
// Navigation.findNavController(getView()).popBackStack(); // 彈出當前堆棧后面的堆棧,如果后面無堆棧則報錯
Navigation.findNavController(getView()).navigateUp(); // 導航到上一個頁面,如果當前是第一個頁面則停留在當前
}
});
}
這里我們可以看到,Navigation返回上一個頁面有兩種主要方式:
- popBackStack:彈出當前堆棧后面的堆棧,如果后面無堆棧則報錯
- navigateUp:導航到上一個頁面,如果當前是第一個頁面則停留在當前
回到回傳數據上,修改完FragmentTwo頁面,接下來我們修改FragmentOne用于接收回傳的數據:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button btnGoTwo = getView().findViewById(R.id.btnGoTwo);
btnGoTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavDirections navDirections = FragmentOneDirections.actionFragmentOneToFragmentTwo("你好,我是fragmentOne發來的消息");
NavController navController = Navigation.findNavController(getView());
navController.navigate(navDirections);
}
});
// 接收回傳的數據
TextView tvMessage = getView().findViewById(R.id.tvMessage);
if (getActivity() instanceof MainActivity) {
String navigationResultData = ((MainActivity) getActivity()).getNavigationResultData();
if (navigationResultData != null) {
tvMessage.setText(navigationResultData);
}
}
}
這一步做完之后,我們便完成了簡單版的數據回傳,我們可以安裝到設備來看一下,但在第二個頁面點擊“返回”時,效果如下:
(七)配置ActionBar
上文我們完成了Navigation頁面跳轉,但和Activity跳轉相比仍有不足之處——我們的ActionBar標題不會跟隨Navigation頁面變化,而且也沒有用于返回的小圖標。
因此,本節我們來解決該問題,Navigation已為我們提供了便捷的解決方案,我們只需配置NavController對ActionBar進行控制,即可解決該問題。
我們打開MainActivity.java,通過四個步驟即可完成配置:
- 第一步,在Activity上獲取NavController:
navController = Navigation.findNavController(this, R.id.navHost);
- 第二步,配置AppBarConfiguration,以便NavController接管ActionBar后能正確進行控制:
appBarConfiguration = new AppBarConfiguration.Builder(R.id.fragmentOne).build();//配置fragmentOne為頂部頁面
- 第三步,配置NavController對ActionBar進行控制
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
- 第四步,配置NavController對后退事件進行控制
@Override
public boolean onSupportNavigateUp() {
// 配置NavController對后退事件進行控制
return NavigationUI.navigateUp(navController, appBarConfiguration);
}
完整的MainActivity.java代碼如下:
public class MainActivity extends AppCompatActivity {
private NavController navController;
private AppBarConfiguration appBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 配置Toolbar到ActionBar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// 配置NavController對ActionBar進行控制
navController = Navigation.findNavController(this, R.id.navHost);
appBarConfiguration = new AppBarConfiguration.Builder(R.id.fragmentOne).build();//配置fragmentOne為頂部頁面
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
}
@Override
public boolean onSupportNavigateUp() {
// 配置NavController對后退事件進行控制
return NavigationUI.navigateUp(navController, appBarConfiguration);
}
// 實現簡單的Navigation頁面回傳數據
private String navigationResultData;
public void setNavigationResultData(String navigationResultData) {
this.navigationResultData = navigationResultData;
}
public String getNavigationResultData() {
return navigationResultData;
}
}
現在我們的Navigation頁面跳轉和Activity跳轉就基本一樣了,我們可以安裝到設備來看一下效果:
棒棒噠!
我們觀察到頁面的標題是fragment_one和fragment_two,這是Navigation根據頁面文件名自動生成的,而實際項目我們通常都需要對這些頁面標題進行修改,那么應該如何進行修改呢?
-
靜態修改標題:我們打開導航圖,點擊選中需要修改標題的頁面(例如fragmentOne),在右邊Attributes窗體的Label輸入框進行修改即可(如下圖)
靜態修改標題 -
動態修改標題:例如我們想使用fragmentOne頁面傳遞過來的標題來作為fragmentTwo頁面的標題,這種情況下我們首先需要為fragmentTwo頁面添加一個Title參數。
步驟和添加Message參數一樣,先打開導航圖,然后點擊選中fragmentTwo頁面,接著在右邊Arguments點擊"+"號,完成Title參數的添加(如下圖)
為fragmentTwo頁面添加Title參數
接下來我們把fragmentTwo頁面的標題設置為Title參數,步驟和靜態修改標題一樣,只不過我們這次需要把Label修改為{參數名}(如下圖)
動態修改標題
添加完參數后,記得Build - Make Project,讓android studio自動生成參數的相關代碼。
最后一步,我們只需要在跳轉時把Title參數攜帶傳遞到fragmentTwo頁面上即可。我們打開FragmentOne.java,修改跳轉的相關代碼:
NavDirections navDirections = FragmentOneDirections
.actionFragmentOneToFragmentTwo("你好,我是fragmentOne發來的消息")
.setTitle("第二個頁面");
NavController navController = Navigation.findNavController(getView());
navController.navigate(navDirections);
現在我們已經成功實現動態修改標題了,我們可以安裝到設備來看一下效果:
(八)切換動畫
我們知道,使用Activity跳轉我們可以實現各種各樣的切換動畫,那么使用Navigation是否也可以呢?答案是肯定的,Navigation為我們提供了完善的解決方案,能夠實現與Activity一樣的切換動畫效果。
首先我們創建四個簡單的切換動畫文件:
anim/slide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
slide_out_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
接著我們把切換動畫應用到Navigation中,打開導航圖,點擊fragmentOne頁面,在右邊Actions一欄中雙擊需要添加切換動畫的路徑(例如fragmentTwo,如下圖)
彈出Update Action窗體,我們找到Transition設置相應的動畫文件即可(如下圖)
修改后點擊Update即可完成Navigation切換動畫的設置!
(九)共享元素動畫
Navigation頁面跳轉同樣也可以實現共享元素動畫!
首先我們創建第三個頁面,用于演示共享元素動畫效果,首先創建一個布局文件(例如fragment_three.xml),其中的ImageView設置有transitionName屬性,為共享元素
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/img"
android:transitionName="@string/transition_img" />
</LinearLayout>
values/strings.xml
<string name="transition_img">transitionBtn</string>
@drawable/img資源
接著創建對應的Fragment(例如FragmentThree.java)
public class FragmentThree extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//設置共享動畫
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_three, container, false);
}
}
同樣添加到導航圖中,然后在導航圖中選中fragmentTwo頁面拖動圓點到fragmentThree頁面上(如下圖),記得Build - Make Project,讓android studio自動生成路徑的相關代碼。
接著我們修改fragmentTwo頁面,讓它實現跳轉到fragmentThree頁面且共享元素動畫,我們先修改fragment_two.xml,增加一個ImageView作為共享元素(如下圖)
<?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">
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="第二個頁面"/>
<Button
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="返回" />
<ImageView
android:id="@+id/ivGoThree"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/img"
android:transitionName="@string/transition_img" />
</LinearLayout>
再修改FragmentThree.java的onActivityCreated方法,讓ImageView點擊時跳轉到fragmentThree頁面,并啟用共享元素動畫
// 對ImageView進行注冊監聽,點擊時跳轉到fragmentThree頁面,并啟用共享元素動畫
final ImageView ivGoThree = getView().findViewById(R.id.ivGoThree);
ivGoThree.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavDirections navDirections = FragmentTwoDirections
.actionFragmentTwoToFragmentThree();
NavController navController = Navigation.findNavController(getView());
// 添加共享元素動畫
FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
.addSharedElement(ivGoThree, ViewCompat.getTransitionName(ivGoThree))
.build();
navController.navigate(navDirections, extras);
}
});
這樣便可實現Navigation頁面跳轉共享元素動畫!