目录
一、简介
JetPack Navigation 是 Android JetPack 组件库中的一个组件,用于简化 Android 应用中的导航和页面间的跳转。它提供了一种统一的方式来管理应用中的导航结构,帮助开发者更容易地实现页面间的跳转和管理。简单来说,Navigation是管理Fragment之间导航的组件库,特别在实现单个Activity多个Fragment的管理模式中非常灵活。
1.1 核心概念和组件
概念 | 描述 |
---|---|
Navigation Graph(导航图) | 导航图是一个 XML 文件,用于定义应用中的导航结构,包含了应用中所有页面之间的导航关系。通过导航图,可以清晰地看到应用的整体导航结构,方便管理和维护。 |
NavHostFragment(导航宿主Fragment) | NavHostFragment 是一个特殊的 Fragment,用于承载应用中的所有 Fragment,并负责管理这些 Fragment 之间的导航。每个 NavHostFragment 都会关联一个导航图,用于指定该 NavHostFragment 中的页面导航规则。 |
NavController(导航控制器) | NavController 是用于管理页面导航的控制器,负责处理页面之间的跳转、返回栈管理、深层链接等操作。可以通过 NavController 来执行页面间的跳转操作。 |
Navigation Component(导航组件) | Navigation Component 是 JetPack Navigation 的核心组件,提供了一系列 API 来简化页面导航的实现。通过 Navigation Component,可以更容易地实现页面间的跳转、传递参数、处理返回栈等操作。 |
1.2 优点
统一的导航结构
:通过导航图可以清晰地定义应用的导航结构,使得整个应用的导航管理更加清晰和统一。类型安全的导航
:通过使用安全参数和类型安全的操作符来执行页面跳转,避免了传统 Intent 跳转中的字符串传参等问题,提高了代码的可维护性和安全性。返回栈管理
:Navigation Component 提供了一套完整的返回栈管理机制,可以方便地管理页面返回栈,实现页面的正确返回和跳转。深层链接支持
:支持通过深层链接直接跳转到应用的指定页面,方便实现推送通知等功能。
二、使用
导航图
(navGraph):这是包含所有导航相关信息的 XML 资源,这些信息包括应用内所有内容区域个体(称为目标,一般都是 Fragment),以及用户可以通过应用跳转的可能路径。
导航宿主
(NavHost):这是用来显示导航图中声明的目标的一个空白容器。导航组件包含一个默认的 NavHost 实现 (NavHostFragment),可用于显示 Fragment 目标。
导航控制器
(NavController):在 NavHost 中管理应用导航的目标,当用户在应用中进行操作时,导航控制器会控制目标的切换。
接下来的示例中,用上述三个核心组件去实现一个简易的Navigation导航demo,
Activity持有NavHostFragment(导航宿主),导航宿主布局指向navGraph(导航图),导航图加载和规划了Fragment的导航方向,使用导航控制器完成跳转。
示意图如下:
2.1 导入依赖
dependencies {
def nav_version = "2.7.7"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:$nav_version"
}
2.2 导航图Navigation Graph
2.2.1 在导航图中放入三个Fragment
Page1Fragment :返回布局、注册点击事件
public class Page1Fragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// return super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.page1fragment, container, false);
}
//点击事件,跳转到第二个Fragment
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btn = view.findViewById(R.id.Page1Button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(view).navigate(R.id.action_page2);
}
});
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Page1Fragment"
android:textColor="@color/blue" />
<Button
android:id="@+id/Page1Button"
android:layout_width="120dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="100dp"
android:background="@color/pink"
android:text="跳转Page2Fragment"
android:textColor="@color/blue" />
</LinearLayout>
Page2Fragment :返回布局、注册点击事件
public class Page2Fragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.page2fragment, container, false);
}
//点击事件,前进和后退点击事件注册
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btnforward = view.findViewById(R.id.Page2forward);
btnforward.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(view).navigate(R.id.action_page3);
// Navigation.findNavController(view).navigateUp();
}
});
Button btnbackward = view.findViewById(R.id.Page2backward);
btnbackward.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(view).navigate(R.id.action_page1);
}
});
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/violet"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Page2Fragment"
android:textColor="@color/blue" />
<Button
android:id="@+id/Page2forward"
android:layout_width="120dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="100dp"
android:background="@color/pink"
android:text="跳转Page3Fragment"
android:textColor="@color/blue" />
<Button
android:id="@+id/Page2backward"
android:layout_width="120dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="100dp"
android:background="@color/pink"
android:text="返回Page1Fragment"
android:textColor="@color/blue" />
</LinearLayout>
Page3Fragment :返回布局、注册点击事件
public class Page3Fragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.page3fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btnforward = view.findViewById(R.id.Page3Back);
btnforward.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(view).navigate(R.id.action_page3_2);
}
});
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bisque"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Page3Fragment"
android:textColor="@color/blue" />
<Button
android:id="@+id/Page3Back"
android:layout_width="120dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="100dp"
android:background="@color/pink"
android:text="返回到Page2Fragment"
android:textColor="@color/blue" />
</LinearLayout>
2.2.2 创建导航图
资源文件夹中创建Navigation根布局
选择+号,添加目的地
从中可以选择本地所有的Fragment
依次添加好上面编写的三个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/nav_graph_main"
app:startDestination="@id/page1Fragment">
<fragment
android:id="@+id/page1Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page1Fragment"
android:label="Page1Fragment" />
<fragment
android:id="@+id/page2Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page2Fragment"
android:label="Page2Fragment" />
<fragment
android:id="@+id/page3Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page3Fragment"
android:label="Page3Fragment" />
</navigation>
连接Fragment的跳转顺序,这样下来,Fragmen1可以跳转到Fragmen2,Fragmen2可以跳转到3…
布局代码会跟着发生变化:
<?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_main"
app:startDestination="@id/page1Fragment">
<!-- 默认启动page1Fragment-->
<!-- 第一个Fragment-->
<fragment
android:id="@+id/page1Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page1Fragment"
android:label="Page1Fragment">
<action
android:id="@+id/action_page2"
app:destination="@id/page2Fragment" />
</fragment>
<!-- 第二个Fragment-->
<fragment
android:id="@+id/page2Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page2Fragment"
android:label="Page2Fragment">
<action
android:id="@+id/action_page3"
app:destination="@id/page3Fragment" />
<action
android:id="@+id/action_page1"
app:destination="@id/page1Fragment" />
</fragment>
<!-- 第三个Fragment-->
<fragment
android:id="@+id/page3Fragment"
android:name="com.henry.jetPackTest.navigationTest.Page3Fragment"
android:label="Page3Fragment">
<action
android:id="@+id/action_page3_2"
app:destination="@id/page2Fragment" />
</fragment>
</navigation>
2.3 导航宿主、导航控制器
将导航宿主注册在Activity的布局文件中,使用BottomNavigationView模拟导航控制器
android:name="androidx.navigation.fragment.NavHostFragment"
必不可少
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="9"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_main" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemTextColor="@color/pink"
app:menu="@menu/menu_fragment" />
</LinearLayout>
菜单布局
<?xml version="1.0" encoding="utf-8"?>
<menu 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">
<item
android:id="@+id/page1Fragment"
android:icon="@drawable/setting"
android:title="第一页"
app:showAsAction="withText" />
<item
android:id="@+id/page2Fragment"
android:icon="@drawable/setting"
android:title="第二页"
app:showAsAction="withText" />
<item
android:id="@+id/page3Fragment"
android:icon="@drawable/setting"
android:title="第三页"
app:showAsAction="withText" />
</menu>
2.4 Activity
public class NavigationTestActivity extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.navigationtest);
//通过 findViewById 方法找到布局文件中 ID 为 nav_view 的 BottomNavigationView 控件,并将其赋值给 bottomNavigationView 变量。
bottomNavigationView = findViewById(R.id.nav_view);
//NavHostFragment 是用于承载导航图的容器。
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.my_nav_host_fragment);
//获取与 NavHostFragment 关联的 NavController,用于管理应用程序的导航操作。
NavController navController = navHostFragment.getNavController();
//与 navController 关联起来,使得底部导航栏中的菜单项可以与导航控制器进行交互,实现页面之间的导航。
NavigationUI.setupWithNavController(bottomNavigationView, navController);
}
}
实现效果:
三、进阶使用
上述demo仅仅设置目标页,其他功能如设置动画、页面间参数传递、fragment回退栈管理、深度链接等参考其他博客:
参考链接:
谷歌官方:Navigation
Android导航组件Navigation从入门到精通
安卓navigation系列——入门篇