Navigation使用

文章目录

  • 先用起来
  • 再加一个fragment
  • 切换动画
  • 传递数据
  • Safe Args
  • BottomNavigationView
  • deeplink

官方文档看起来

先用起来

1、引入依赖

	implementation 'androidx.navigation:navigation-fragment:2.3.0'
    implementation 'androidx.navigation:navigation-ui:2.3.0'

2、res 下 创建 navigation 资源文件夹
Navigation使用_第1张图片
Navigation使用_第2张图片

3、navigation 资源文件夹下创建资源文件 navigation.xml,这个文件也叫做 Navigation Graph
Navigation使用_第3张图片
Navigation使用_第4张图片
navigation.xml 内容如下

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/navigation">

</navigation>

4、创建 RootFragment,布局为 fragment_root.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary"
    tools:context=".MainActivity"
    android:gravity="center">
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RootFragment"
        android:textColor="@android:color/white"/>

LinearLayout>

5、打开navigation.xml 切换布局模式,添加RootFragment
Navigation使用_第5张图片
6、在项目的 MainActivity 布局 activity_main.xml 中,切换到布局模式,左侧 palette 搜索到 Navhoatfragment 拖拽到布局中,使其 宽高都 match_parent

现在 activity_main 中代码如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/navigation" />
</LinearLayout>

7、运行程序即可,需要注意 MainActivity 需要 extends AppCompatActivity ,否则会报错 在这里插入图片描述
Navigation使用_第6张图片
可以看看刚才的 navigation.xml
Navigation使用_第7张图片

跟之前相比,多了 fragment 节点,以及根节点上多了一个 startDestination 属性。在 Navigation 中我们使用 Destination(目标)来描述 Fragment 之间的跳转关系。这里的 startDestination 代表的就是这个是 Navigation 整个页面跳转管理栈的最根级页面

再来看看那个添加到 MainActivity 页面的 NavHostFragment 组件。它其实就是一个布局文件中的 fragmen 组件,跟我们正常使用的没什么不同,非要说不同,那就是其中的 name、defaultNavHost 以及 navGraph 这三个属性了

name 属性我们都知道,navGraph 属性里面的值是刚才创建 Navigation Graph,就是把 Navigation Graph 引用到了这个 NavHostFragment 中。最后一个 defaultNavHost 就是拦截系统返回按钮的点击事件的

再加一个fragment

我们再加一个页面(SettingsFragment)。尝试着从 RootFragment 页面点击按钮切换到 SettingsFragment 页面。然后在 SettingsFragment 页面点击按钮返回到 RootFragment

navigation.xml 布局模式跟之前一样的操作,添加 SettingFragment,多了一步就是点击 RootFragment 右边的小圆点然后牵引到右侧的 SettingsFragment。这样他们两个就建立一种关系
Navigation使用_第8张图片
现在查看 navigation.xml 的代码,除了增加了一个 fragment 节点之外,原来的 RootFragment 的节点上还增加了一个子节点 action 。事实上,action 节点就是用来描述 Fragmen 之间的页面跳转的关系的,其中 destination 属性的值就是目标 fragment 的 id
Navigation使用_第9张图片
我们给 RootFragment 布局中的 TextView 添加点击事件,通过 Navigation 找到一个叫 NavController 的东西,然后执行 navigate 方法,这个方法里面传的值就是刚才 RootFragment 子节点 action 的 id 的值。先运行一下看看效果

textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Navigation.findNavController(textView).navigate(R.id.action_rootFragment_to_settingFragment);
            }
        });

Navigation使用_第10张图片

点击 RootFragment 跳转 SettingFragment,此时点击系统的返回键,是能返回到 RootFragment。这就是 MainActivity 中 NavHostFragment 组件的属性 app:defaultNavHost=“true” 起到的作用

app:defaultNavHost=”true”这个属性意味着你的Fragment将会 拦截系统Back键的点击事件(因为系统的back键会直接关闭Activity而非切换Fragment)。让 Navigation 处理返回事件,点返回按钮时并不是返回上一个 Activity,而是返回上一个「页面」,上一个「页面」有可能是 Activity,也可能是 Fragment

下面给 SettingFragment 的文字增加点击事件

tv_name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Navigation.findNavController(tv_name).popBackStack();
            }
        });

Navigation使用_第11张图片

切换动画

在 navigation.xml 的视图模式中,选中箭头,在Animations中选中之前写好的动画即可
Navigation使用_第12张图片
这样代码中的 action节点会自动增加代码
Navigation使用_第13张图片
enterAnim:目标页进来的动画
exitAnim:当前页退出的动画
popEnterAnim:按下返回键,目标页进来的动画
popExitAnim:按下返回键,当前页退出的动画

也可以使用 java代码 实现

NavOptions options = new NavOptions.Builder()
                .setEnterAnim(R.anim.slide_left_in)
                .setExitAnim(R.anim.slide_left_out)
                .setPopEnterAnim(R.anim.slide_left_in)
                .setPopExitAnim(R.anim.slide_left_out)
                .build();
        textView = v.findViewById(R.id.tv_name);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Navigation.findNavController(textView).navigate(R.id.action_rootFragment_to_settingFragment,null,options);
            }
        });

传递数据

从上边的代码中可以看到,navigate 的第二个参数我们传了 null,
我们调用了 navigate 这个方法,其中第二个参数是 Bundle 类型,我们填入了 null,那如果正常填了值,Bundle 就是传递到 SettingsFragment 了

Bundle bundle = new Bundle();
bundle.putString("name","Errol");
Navigation.findNavController(textView).navigate(R.id.action_rootFragment_to_settingFragment,bundle,options);

如果想让 SettingFragment 有默认值可以在 navigation.xml 中设置 argument
Navigation使用_第14张图片

获取数据时,SettingFragment中

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            String mParam1 = getArguments().getString("name");
            Log.d("Budle",""+mParam1);
        }
    }

Safe Args

可在目标之间导航和传递数据时提供类型安全的 Gradle 插件

在项目根目录的 build.gradle 中加入

classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"

如图:
Navigation使用_第15张图片
然后在你项目app 或是 module 的目录下的 build.gradle 文件夹加入:

apply plugin: "androidx.navigation.safeargs"

如图:
Navigation使用_第16张图片
现在我们就来从 RootFragmet 传递一个类型为 Int 的年龄字段到 SettingsFragmen 吧。navigation.xml 的图形界面中,选中 SettingsFragment,然后再右侧属性面板上找到 Argments 点击旁边的➕
Navigation使用_第17张图片
然后 rebuild project,会在一下路径生成 RootFragmentDirections 和 SettingFragmentArgs 两个文件
Navigation使用_第18张图片
RootFragment 中

String nickName = "master";
RootFragmentDirections.ActionRootFragmentToSettingFragment action =
                RootFragmentDirections.actionRootFragmentToSettingFragment().setNickName(nickName);

textView.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
		Navigation.findNavController(textView).navigate(action);
    }
});

SettingFragment 中

String nickName = SettingFragmentArgs.fromBundle(getArguments()).getNickName();
tv_name.setText(nickName);

这比之前我们用 Bundle 传值要方便的多啦,而且再也不用担心 Key 写错的问题了

BottomNavigationView

1、创建3个fragment:OneFragment、TwoFragment、ThreeFragment,布局中就一个 TextView仅仅为了展示,在 tab_navigation.xml 中把这三个 fragment 添加进去

<?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" android:id="@+id/tab_navigation"
    app:startDestination="@id/oneFragment">

    <fragment
        android:id="@+id/oneFragment"
        android:name="com.xx.xx.OneFragment"
        android:label="OneFragment" />
    <fragment
        android:id="@+id/twoFragment"
        android:name="com.xx.xx.TwoFragment"
        android:label="TwoFragment" />
    <fragment
        android:id="@+id/threeFragment"
        android:name="com.xx.xx.ThreeFragment"
        android:label="ThreeFragment" />
</navigation>

2、新建 TabActivity ,布局为 activity_tab,在布局中拖动一个 BottomNavigationView 到底部,上边剩余部分放 NavHostFragment,navGrah 选择我们新建的 tab_navigation.xml

activity_tab 的代码如下:其中menu的设置看第3步

<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=".TabActivity">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nv_bottom_menu"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        app:itemHorizontalTranslationEnabled="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:menu="@menu/bottom_menu"
        android:background="@android:color/white"/>

    <fragment
        android:id="@+id/fragment2"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@+id/nv_bottom_menu"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/tab_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

3、在 activity_tab 的 Design 模式中,选中 BottomNavigationView ,在右侧会出现 menu 属性,点击右侧按钮,来添加一个
Navigation使用_第19张图片
Navigation使用_第20张图片
bottom_menu内容:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/oneFragment"
        android:icon="@mipmap/btn_one"
        android:title="One" />
    <item
        android:id="@+id/twoFragment"
        android:icon="@mipmap/btn_two"
        android:title="Two" />
    <item
        android:id="@+id/threeFragment"
        android:icon="@mipmap/btn_three"
        android:title="Three" />
</menu>

现在看 activity_tab 已经变成了这样
Navigation使用_第21张图片
4、TabActivity中添加以下代码

NavHostFragment hostFragment = (NavHostFragment) getSupportFragmentManager()
                .findFragmentById(R.id.fragment2);
        BottomNavigationView navMenu = findViewById(R.id.nv_bottom_menu);
        if (hostFragment != null) {
            NavController navController = hostFragment.getNavController();
            NavigationUI.setupWithNavController(navMenu, navController);
        }

第一行,findFragmentById 里填写的 id 就是我们在 tab_activity.xml 中 name 属性是 NavHostFragment 节点的 id

然后再通过 NavigationUI.setupWithNavController() 将二者进行想管理,这样只要我们点击底部导航菜单就是自动实现 Fragment 的之间的切换

事实上,NavigationUI.setupWithNavController() 这个方法有很多重载方法,不仅仅只是用在BottomNavigationView,还有 NavigationView 等,在这里就不一一介绍了感兴趣的可以去试试

Navigation使用_第22张图片

deeplink

Deeplink,简单讲,就是你在手机上点击一个链接之后,可以直接链接到app内部的某个页面,而不是app正常打开时显示的首页。不似web,一个链接就可以直接打开web的内页,app的内页打开,必须用到deeplink技术

1、准备一个 DeepLinkFragment ,页面只展示名称,代码不写了

2、在我们之前的 navigation.xml 中把这个 DeeplinkFragment加进来,然后增加一个 deeplink

Navigation使用_第23张图片
navigation.xml 的代码变成了
Navigation使用_第24张图片
3、在 manifest 的承载 DeepLinkFragment 的 Activity 节点内引入你的 Navigation Graph
那里填的 url 后面大括号包裹着的是传入 DeepLinkFragment 的值,myarg 是 key,通过 Bundle 进行传递

这篇文章里有两个 Navigation Graph 文件,一个是用于 RootFragment 与 SettingFragment 进行跳转的 navigation.xml,一个是用于底部导航菜单栏的 tab_navigation.xml,我把 DeepLinkFragment 放在了 navigation.xml 中,所以下面的值是 @navigation/navigation

AndroidManifest.xml 中在 MainActivity 下增加
在这里插入图片描述
Navigation使用_第25张图片
如果 DeeplinkFragment 写了接收参数的代码

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            String mParam1 = getArguments().getString("myarg");
            Log.d("myarg",""+mParam1);
        }
    }

那么在打开 DeeplinkFragment 时还能接收到这个参数
在这里插入图片描述

一个App真的只需要一个Activity

你可能感兴趣的:(Android从入门到放弃)