簡介
Navigation導航編輯器旨在簡化Android開發中導航的實現,可以幫助我們很好的處理Activity和fragment之間通過FragmentTransaction交互的復雜性,也可以很好的處理頁面的轉場效果;Deeplink的支持,繞過activity直接跳到fragment;並且傳遞參數更安全。在Android Studio3.2可以使用。
基本使用
- 引用相關依賴
implementation "android.arch.navigation:navigation-fragment:1.0.0-rc01" // use -ktx for Kotlin
implementation "android.arch.navigation:navigation-ui:1.0.0-rc01"
- 創建資源文件
- 創建Fragment文件
class IndexFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.index_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var args = arguments?.let { IndexFragmentArgs.fromBundle(it) }
top_bar_title.text = args!!.topBarTitle
txt_desc.text = "${args!!.topBarTitle}頁面"
}
}
class BallFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.ball_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var args = arguments?.let { BallFragmentArgs.fromBundle(it) }
top_bar_title.text = args!!.topBarTitle
txt_desc.text = "${args!!.topBarTitle}頁面"
}
}
- 創建navigation導航圖
<?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"
android:id="@+id/nav_graph"
app:startDestination="@id/indexFragment">
<!-- app:startDestination是起始Destination,必須指定 -->
<fragment android:id="@+id/indexFragment"
android:name="com.fomin.demo.bar.IndexFragment"
android:label="IndexFragment"
tools:layout="@layout/index_fragment">
<!--參數傳遞-->
<argument android:name="topBarTitle"
app:argType="string"
android:defaultValue="主頁"/>
<!--跳轉動作-->
<action android:id="@+id/action_indexFragment_to_ballFragment"
app:destination="@id/ballFragment"/>
</fragment>
<fragment android:id="@+id/ballFragment"
android:name="com.fomin.demo.bar.BallFragment"
android:label="BallFragment"
tools:layout="@layout/ball_fragment">
<argument android:name="topBarTitle"
app:argType="string"
android:defaultValue="足球"/>
</fragment>
</navigation>
- Activity布局文件添加fragment
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/nav_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"/>
</LinearLayout>
在Activity中添加如下代碼
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
}
override fun onSupportNavigateUp(): Boolean {
return Navigation.findNavController(this, R.id.nav_fragment).navigateUp()
}
}
- 配置Fragment的跳轉
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var args = arguments?.let { IndexFragmentArgs.fromBundle(it) }
top_bar_title.text = args!!.topBarTitle
btn_goto_ball.setOnClickListener { Navigation.findNavController(it).navigate(R.id.action_indexFragment_to_ballFragment) }//點擊跳轉時間
}
- 配置Fragment回退事件
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var args = arguments?.let { BallFragmentArgs.fromBundle(it) }
top_bar_title.text = args!!.topBarTitle
top_bar_back.visibility = if (args!!.showBack == 1) View.VISIBLE else View.GONE
txt_desc.text = "${args!!.topBarTitle}頁面"
top_bar_back.setOnClickListener { Navigation.findNavController(it).popBackStack() }//回退事件
}
好了,Navigation入門講解完了,上面代碼對於Fragment 並非是通過原生的 FragmentManager 和 FragmentTransaction 進行控制的,而是通過以下Navigation.findNavController(params)進行的控制。接下來會對Navigation詳細講解。
導航視圖
- app:startDestination
此屬性位於navigation 根節點上,是導航器默認加載在Activity的視圖,是必須設置的。
<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"
android:id="@+id/nav_graph"
app:startDestination="@id/indexFragment">
<fragment android:id="@+id/ballFragment"
android:name="com.fomin.demo.bar.BallFragment"
android:label="BallFragment"
tools:layout="@layout/ball_fragment"/>
</navigation>
- fragment/activity
navigation可以添加fragment和activity的視圖,需要關注的屬性android:id和android:name,name是所在Fragmet/Activity類所在包名,id就不解釋了,眾所周知。
- argument
使用參數傳遞,需要module的build.gradle添加:apply plugin: 'androidx.navigation.safeargs'
<fragment android:id="@+id/ballFragment"
android:name="com.fomin.demo.bar.BallFragment"
android:label="BallFragment"
tools:layout="@layout/ball_fragment">
<argument android:name="topBarTitle"
app:argType="string"
android:defaultValue="足球"/>
</fragment>
視圖之間的參數傳遞屬性,argType可以支持string、integer、reference,long,float,boolean和Parcelable對象等。增加屬性之后需要Rebuild一下,IDE會生成相關視圖的Args類。如:
public class BallFragmentArgs implements NavArgs {
省略....
@NonNull
public String getTopBarTitle() {
return (String) arguments.get("topBarTitle");
}
省略....
}
參數傳遞
btn_goto_ball.setOnClickListener {
val bundle = Bundle()
bundle.putString("topBarTitle", "籃球")
Navigation.findNavController(it).navigate(R.id.action_indexFragment_to_ballFragment, bundle)
}
獲取傳遞參數值
var args = arguments?.let { BallFragmentArgs.fromBundle(it) }
top_bar_title.text = args!!.topBarTitle
- action
動作,即跳轉動作,從視圖A跳轉到視圖B的動作
<fragment android:id="@+id/indexFragment"
android:name="com.fomin.demo.bar.IndexFragment"
android:label="IndexFragment"
tools:layout="@layout/index_fragment">
<!--跳轉動作-->
<action android:id="@+id/action_indexFragment_to_ballFragment"
app:destination="@id/ballFragment"/>
</fragment>
app:destination的屬性,聲明了這個行為導航的目的地id為ballFragment的視圖
android:id 這個id作為Action唯一的 標識,在視圖類的某個點擊事件中,我們通過id指向對應的行為
btn_goto_ball.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.action_indexFragment_to_ballFragment)
}
平常頁面跳轉都會使用到相關的轉場動畫,action也為轉場動畫提供了enterAnim、exitAnim、popEnterAnim、popExitAnim四個動畫屬性,可以設置相關的anim動畫資源。
此外,還提供了一個app:popUpTo屬性,它的作用是聲明導航行為將返回到id對應的Fragment。
- Deep Link
使用deep-link可以創建深層鏈接,類似activity的自定義URL使用Scheme方式來跳轉,可以直接跳轉到指定fragment/activity
<fragment android:id="@+id/ballFragment"
android:name="com.fomin.demo.bar.BallFragment"
android:label="BallFragment"
tools:layout="@layout/ball_fragment">
<deepLink app:uri="http://www.fomin.com/login"/>
</fragment>
在Manifest.xml添加規則
<activity android:name=".login.LoginActivity">
<nav-graph android:value="@navigation/nav_graph2"/>
</activity>
NavHostFragment
NavHostFragment在布局中提供了一個區域,用於進行Navigation。
<fragment
android:id="@+id/nav_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph2"/>
android:name指定NavHostFragment包名,必填項;app:navGraph指定navigation的資源文件;app:defaultNavHost="true"可確保NavHostFragment攔截系統“后退”按鈕。 也可以在代碼上設置,如:
override fun onSupportNavigateUp(): Boolean {
return Navigation.findNavController(this, R.id.nav_fragment).navigateUp()
}
導航類
navigation提供了Navigation和NavController的類;Navigation此類提供了用於從應用程序中的各個常見位置查找相關NavController實例的實用程序,或用於執行導航以響應UI事件的實用程序;而NavController管理NavHost中的應用程序導航。