jetpack之Navigation

概述
组成

导航组件由以下三个关键部分组成:

  • 导航图:在一个集中位置包含所有导航相关信息的 XML 资源。这包括应用内所有单个内容区域(称为目标)以及用户可以通过应用获取的可能路径。
  • NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示 Fragment 目标。
  • NavController:在 NavHost 中管理应用导航的对象。当用户在整个应用中移动时,NavController 会安排 NavHost 中目标内容的交换。
使用

1.要求

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

2.添加项目依赖

1
2
3
// navigation
implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui:2.2.2'

3.创建Navigation

  • res文件夹,选中点击右键选择New > Android resource file. 如下图:

1

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

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

  • 打开nav_main.xml,选中design模式

  • 进入design模式后,点击下面这个New Destination 按钮

  • 选择Create blank destination

  • 命名Fragment名称为FragmentA,如下图

    那个 include fragment factory methods? 选中的话会帮你自动重写一些fragment的方法,像onCreate(),onCreateView()和构造方法等,看起来会有点乱,自己实现也行

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

  • 点击切换到Text模式,对应nav_main.xml对应生成的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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_main"
app:startDestination="@id/fragmentA">

<fragment
android:id="@+id/fragmentA"
android:name="com.ccc.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="com.ccc.navigationdemo.FragmentB"
android:label="fragment_b"
tools:layout="@layout/fragment_b" />
</navigation>
  • 说明

    • 里面有两个fragment标签,就是我们刚才创建的页面A和B。

    • 其中fragmentA中的action是一个节点,destination就是要导航到fragmentB。这个就是我们刚才上一步创建导航连接自动实现的代码。

  • MainActivity里面对应不需要任何操作,设置好布局即可

1
2
3
4
5
6
7
8
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
  • 接下来,在activity_main里面创建一个fragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph = "@navigation/nav_main"
app:defaultNavHost = "true"
/>

</LinearLayout>
  • 来说明一下后面三个属性

    • name属性,指定在布局中要实例化NavHostFragment

    • navGraph属性,是将NavHostFragment与我们刚才创建的navigation进行关联

    • defaultNavHost属性app:defaultNavHost="true",意思是NavHostFragment来拦截系统返回按钮

下面来实现页面跳转和数据传递

  • fragment_a.xml如下设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<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:gravity="center"
android:orientation="vertical"
android:layout_margin="20dp"
tools:context=".FragmentA">

<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Fragment A" />

<Button
android:id="@+id/btn_to_b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击跳转到 Fragment B"/>
</LinearLayout>
  • fragment_b.xml 如下设置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<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:gravity="center"
android:orientation="vertical"
tools:context=".FragmentB">

<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Fragment B" />

<TextView
android:layout_margin="20dp"
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="show"/>

</LinearLayout>
  • FragmentA中添加Button点击跳转事件,跳到FragmentB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class FragmentA extends Fragment {

private Button button;

private View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_a, container, false);
return view;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
button = view.findViewById(R.id.btn_to_b);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

// 传递参数
Bundle bundle = new Bundle();
bundle.putString("name","chrome");

//不带参数
//Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB);

//带参数
Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB,bundle);
}
});
}
}
  • 说明

    • 这里的 id = action_fragmentA_to_fragmentB,就是上面设置的导航action的id

  • 传递参数

  • 方式1:通过Bundle方式
1
2
3
4
// 传递参数
Bundle bundle = new Bundle();
bundle.putString("name","chrome");
Navigation.findNavController(v).navigate(R.id.action_fragmentA_to_fragmentB,bundle);

b页面接收:

1
2
3
4
5
6
//通过 getArguments 来获取传递的参数
Bundle bundle = getArguments();
String text = bundle.getString("name");

tv = view.findViewById(R.id.show);
tv.setText(text);
  • 方式2:使用Safe Args 传递安全的数据

这玩意比较麻烦感觉,用到时候去官网再学吧

https://developer.android.google.cn/guide/navigation/navigation-pass-data#Safe-args

  • 运行一下,看一下效果。

两篇学习博客

https://www.jianshu.com/p/cd925c2398cb

https://www.jianshu.com/p/729375b932fe

0%