初尝Android Jetpack 之Navigation


什么是 Navigation

  • The Navigation Architecture Component simplifies the implementation of navigation in an Android app

Navigation能做什么

利用Navigation组件对 Fragment 的原生支持,您可以获得架构组件的所有好处(例如生命周期和 ViewModel),同时让此组件为您处理 FragmentTransaction 的复杂性。此外,Navigation组件还可以让您声明我们为您处理的转场。它可以自动构建正确的“向上”和“返回”行为,包含对深层链接的完整支持,并提供了帮助程序,用于将导航关联到合适的 UI 小部件,例如抽屉式导航栏和底部导航。

怎么使用Navigation

1.目前仅在Android Studio 3.2(目前是preview)版本以上才支持

2.添加项目依赖

新建一个项目,
(1)在project的build.gradle中,添加项目的依赖

buildscript {
    ...
    repositories {
            google()
    }
    dependencies {
            ...
            classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01'
    }
  }

(2)在app的build.gradle中添加如下依赖

apply plugin: 'androidx.navigation.safeargs'
dependencies {
    ...
    def nav_version = "1.0.0-alpha01"

    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin 
    // optional - Test helpers
    androidTestImplementation "android.arch.navigation:navigation-testing:$nav_version" // use -ktx for Kotlin
}

(3)创建Navigation

  • 在新建的项目中,找到res文件夹,选中点击右键选择 New > Android resource file. 如下图:


    1.png
  • 在弹出的对话框中,
    File name 一栏,填写例如"nav_main",Resource type一栏选择 Navigation,然后点击OK,如下图:


    2.png
  • 选择创建好之后,会发现在res文件夹目录下面,会自动生成一个navigation文件夹,然后刚才我们创建的xml文件nav_main也放在里面,如下图:


    image.png
  • 点击选中nav_main.xml双击打开,默认是Design模式,点击
    image.png

    ,在弹出的对话框选择 Create blank destination
    如下图:


    image.png
  • 命名Fragment名称为FragmentA,如下图:


    image.png
  • 同上,再创建一个FragmentB
  • 在design模式下,创建导航链接,鼠标点击FragmentA右边中间圆圈不放拖动到FragmentB上释放鼠标即可,如下图:


    image.png
  • 点击切换到Text模式,对应nav_main.xml对应生成的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="navigation.xxw.com.navigationdemo.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB" />
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="navigation.xxw.com.navigationdemo.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" />
</navigation>
  • 其中fragmentA中的action是一个节点,destination就是要导航到fragmentB
  • MainActivity里面对应不需要任何操作,设置好布局即可
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
  • 接下来,在activity_main里面创建一个fragment,
    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  • 往里添加name属性,指定在布局中要实例化NavHostFragment
android:name="androidx.navigation.fragment.NavHostFragment"
  • 添加navGraph属性,是将NavHostFragment与我们刚才创建的navigation进行关联
app:navGraph="@navigation/nav_main"
  • 添加defaultNavHost属性,app:defaultNavHost="true",意思是NavHostFragment来拦截系统返回按钮
app:defaultNavHost="true"
  • 而如果我们不设置defaultNavHost属性,可以通过Navigation中的API对应navigateUp方法来实现返回
Navigation.findNavController(it).navigateUp()
  • 最终我们定义的fragment就算定义好了,如下:
   <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_main" />
     <Button
        android:id="@+id/btn_go_to"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="点击跳转到Fragment B"
        app:layout_constraintTop_toBottomOf="@id/text" />
  • 在FragmentA中添加Button点击跳转事件,跳到FragmentB
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        view?.findViewById<Button>(R.id.btn_go_to)?.setOnClickListener {
            Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB)
        }
    }
  • 这里的id=action_fragmentA_to_fragmentB,就是上面设置的导航action的id
  • 最后运行跑一下
  • 传递参数,第一种方式,通过bundle方式
        var bundle = Bundle()
        bundle.putString("name","zhangsan")
        view?.findViewById<Button>(R.id.btn_go_to_bundle)?.setOnClickListener {
            Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB,bundle)
        }
  • 在Fragment B页面通过arguments 来获取传过来的bundle,
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        var bundle = arguments
        if (bundle != null) {
            var name = bundle?.getString("name")
            view.findViewById<TextView>(R.id.textB).text = "来自Fragment A页面的参数:"+name
        }
    }
  • 传递参数,第二种方式,通过设置argument标签,在需要接收参数的FragmentB页面中设置argument标签
    <fragment
        android:id="@+id/fragmentB"
        android:name="navigation.xxw.com.navigationdemo.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" >
        <argument android:name="text" android:defaultValue="Hello" app:type="string"/>
    </fragment>

其中name类似于map中的key,defaultValue是默认值,type对应是数据类型
在Fragment A页面传值通过自动生成的FragmentBArgs来进行实现bundle

  val bundle1 = FragmentBArgs.Builder().setText("我是通过argument标签实现传值").build().toBundle()
  view?.findViewById<Button>(R.id.btn_go_to_argument)?.setOnClickListener {
     Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB,bundle1)
 }

同样在FragmentB页面中通过FragmentBArgs来获取参数

//通过arguments获取参数
        val text = FragmentBArgs.fromBundle(arguments).text
        view.findViewById<TextView>(R.id.textB).text = "arguments方式获取参数:"+text
  • PS:如果没有在调用没有自动生成FragmentBArgs方法,查看在app的build.gradle中添加如下依赖
apply plugin: 'androidx.navigation.safeargs'
  • 添加fragment之间跳转动画,可以通过action直接添加,在res文件夹创建anim文件夹,放入四个动画slide_in_right.xml、slide_out_left.xml、slide_in_left.xml、slide_out_right.xml,然后在action中添加,如下:
    <fragment
        android:id="@+id/fragmentA"
        android:name="navigation.xxw.com.navigationdemo.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >

        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"/>
    </fragment>
  • 同样也可以在代码中通过设置NavOptions实现,具体如下:
        val options = NavOptions.Builder()
                .setEnterAnim(R.anim.slide_in_right)
                .setExitAnim(R.anim.slide_out_left)
                .setPopEnterAnim(R.anim.slide_in_left)
                .setPopExitAnim(R.anim.slide_out_right)
                .build()

        view?.findViewById<Button>(R.id.btn_go_to_anim)?.setOnClickListener {
            Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB,null,options)
        }
  • 谢谢浏览!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,803评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    wgl0419阅读 6,267评论 1 9
  • 亲爱的女儿: 7月16日,这天是你们高一新生到校军训的第一天。海山学校依山傍海,风景秀丽。校区座落在“石老人国家旅...
    陈虹_dd45阅读 211评论 0 0
  • 9. 鄂州城 瑜娘自从在秦元龙处得知。李大牛留下的宝刀,乃是其恩师相送,意义重大。瑜娘愈加相信李大牛会回来,心里更...
    三悟阅读 488评论 0 1
  • 今夜,月华如练 我望见她的鸾镜朱颜 如花笑靥款款出现 梦中我曾见 天安门前的肃穆庄严 那一抹红色染遍万里江山 梦中...
    碧绿的心阅读 234评论 0 0