Android Navigation使用

简介

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"

图片

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}页面"
    }
}
<?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>
<?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()
    }
}
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) }//点击跳转时间
}
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详细讲解。

导航视图

此属性位于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>

navigation可以添加fragment和activity的视图,需要关注的属性android:id和android:name,name是所在Fragmet/Activity类所在包名,id就不解释了,众所周知。

使用参数传递,需要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

动作,即跳转动作,从视图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可以创建深层链接,类似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在布局中提供了一个区域,用于进行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中的应用程序导航。

Android Navigation使用

全文结束