Navigation
Navigation是google官方新增的用于Fragment管理的一個架構(gòu)組件,可以很方便的像管理Activity一樣管理你的Fragment,并且google在AndroidStudio3.2中加入了可視化手動拖拽式的組件
基本概念
- App - 一個頁面棧結(jié)構(gòu)
- Destination - 一個頁面的子頁面,通常是一個Fragment,但也支持其他類型
- Activity
- 其他NavigationGraph
- 自定義Destination
- Deep-Link - 鏈接形式的跳轉(zhuǎn)(URI形式的鏈接)
- NavigationGraph - 一組Destination構(gòu)成的頁面結(jié)構(gòu)(一個Navigation xml文件表示)
- Actions - 連接不同Destination的行為
Navigation的編寫原則
- 每個App必須有個固定的起點,對應(yīng)的,每個Activity中也需要有個固定的起點Fragment
- 使用Stack結(jié)構(gòu)來管理Navigation狀態(tài),起始頁面在Stack底部,當前頁面在Stack的top,在Navigation中使用destination來描述一個頁面,可以是Activity也可以是Fragment
- 開始destination不顯示上一頁按鈕,如果是從其他App頁面通過
deep-link
(下面會講到)導(dǎo)航過來的,按上一頁返回的是父級頁面而不是其他App - Back和Up(上一頁)在大部分情況下是等同的,除非Back按鈕按下后會使得App退出
- Deep-link 和 普通Navigation 跳轉(zhuǎn)形成的頁面棧應(yīng)該是一樣的
Navigation簡單例子的編寫步驟
1.有一個Activity,在layout文件中聲明一個fragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.apm29.yjw.demo.ui.main.MainActivity">
<fragment
android:layout_width="match_parent"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_nav_graph"
app:defaultNavHost="true"
android:layout_height="match_parent"/>
</FrameLayout>
- app:defaultNavHost="true" 表示使用默認的導(dǎo)航host,自動覆蓋Activity的back按
鈕,不用再覆寫[AppCompatActivity.onSupportNavigateUp()
]
(https://developer.android.google.cn/reference/android/support/v7/app/AppCompatActivity)方法 - app:navGraph="@navigation/main_nav_graph"指向你的nav_graph文件
當然Navigation也提供了代碼式的引入形式
val finalHost = NavHostFragment.create(R.navigation.main_nav_graph)
supportFragmentManager.beginTransaction()
.replace(R.id.nav_host, finalHost)
.setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
.commit()
2.編寫main_nav_graph.xml文件(文件名自己定義)
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.apm29.yjw.demo.ui.main.MainFragment"
android:label="MainFragment">
<action
android:id="@+id/action_mainFragment_to_mainDetailFragment"
app:destination="@id/mainDetailFragment" />
</fragment>
<fragment
android:id="@+id/mainDetailFragment"
android:name="com.apm29.yjw.demo.ui.main.MainDetailFragment"
android:label="MainDetailFragment">
<argument android:name="id"
app:argType="String"
android:defaultValue="0"/>
<deepLink
android:autoVerify="true"
app:uri="www.main.detail/{id}" />
</fragment>
</navigation>
- app:startDestination="@id/mainFragment" 指定初始頁面
- fragment節(jié)點表示一個destination
- name屬性指定Fragment的全路徑名
- label是在可視化界面的顯示名稱
- action標簽定義了Destination之間的跳轉(zhuǎn)行為
- 將Navigation綁定到UI組件
其中有一個關(guān)鍵的類
NavController
,通過以下方法得到其實例
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
然后使用它的navigate
方法導(dǎo)航到你想去的Destination,接收參數(shù)可以是一個ActionId(定義在nav_graph文件中的),使用navigateUp
,popBackStack
對應(yīng)Up和Back按鍵,另外還可以加入Bundle,NavOption,ShareElements等,參考https://developer.android.google.cn/topic/libraries/architecture/navigation/navigation-implementing#Create-transition
// Rename the Pair class from the Android framework to avoid a name clash
import android.util.Pair as UtilPair
...
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
UtilPair.create(imageView, "header_image"),
UtilPair.create(titleView, "header_title"))
val extras = ActivityNavigator.Extras(options)
view.findNavController().navigate(R.id.details,
null, // Bundle of args
null, // NavOptions
extras)
使用SharedElement
val extras = FragmentNavigatorExtras(
imageView to "header_image",
titleView to "header_title")
view.findNavController().navigate(R.id.confirmationAction,
null, // Bundle of args
null, // NavOptions
extras)
先給navigate()方法添加extra參數(shù),包含了一些<View,String>的Pair,View表示sharedElement,String則是transitionName,可以在xml中確定也可以代碼確定
<ImageView
android:transitionName="@string/app_icon"
android:id="@+id/imageView"
app:srcCompat="@mipmap/ic_launcher_round" />
imageView.transitionName = getString(R.string.app_icon)
然后再設(shè)置Fragment中的SharedElementReturnTransition和SharedElementEnterTransition
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
sharedElementReturnTransition = AutoTransition()
sharedElementEnterTransition = AutoTransition()
}
實際上Navigation 1.0.0 alpha06才加入的這個功能,并不是很完善,只為我們完成了SharedELement的添加,剩余工作還是我們自己完成