用于页面跳转,功能很简单,下面看下用法吧
- 导入需要的库
def nav_version = "2.3.2"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
- 完成fragment的常规代码
- 创建navigation目录,完成nav_graph.xml
<?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/FirstFragment">
<fragment
android:id="@+id/FirstFragment"
android:name="com.example.jetpack_demo.fragment.Nav1Fragment"
android:label="@string/first_fragment_label"
tools:layout="@layout/fragment_first">
<action
android:id="@+id/action_FirstFragment_to_SecondFragment"
app:destination="@id/SecondFragment" />
</fragment>
<fragment
android:id="@+id/SecondFragment"
android:name="com.example.jetpack_demo.fragment.Nav2Fragment"
android:label="@string/second_fragment_label"
tools:layout="@layout/fragment_second">
<action
android:id="@+id/action_SecondFragment_to_FirstFragment"
app:destination="@id/FirstFragment" />
</fragment>
</navigation>
fragment 标签中注册Fragment ,action 标签中定义跳转动作,在页面上跳转时通过定义的action进行跳转
- 完成activity 布局文件
<?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"
android:orientation="vertical"
tools:context=".activity.NavigationSimpleActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
/>
<!-- 底部导航-->
<!-- <com.google.android.material.bottomnavigation.BottomNavigationView-->
<!-- android:id="@+id/nav_view"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="50dp"-->
<!-- app:itemTextColor="#ff0000"-->
<!-- app:menu="@menu/menu"/>-->
</LinearLayout>
app:defaultNavHost="true" 的作用:拦截系统back键 app:navGraph="@navigation/nav_graph" 的作用:设置跳转路由
- 完成activity.java的内容
public class NavigationSimpleActivity extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigation_simple);
// 底部导航功能
// NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.my_nav_host_fragment);
// bottomNavigationView = findViewById(R.id.nav_view);
// NavController controller = navHostFragment.getNavController();
// NavigationUI.setupWithNavController(bottomNavigationView,controller);
}
@Override
public boolean onSupportNavigateUp() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.my_nav_host_fragment);
return NavHostFragment.findNavController(fragment).navigateUp();
}
}
- 完善Fragment中的按钮跳转功能
public class Nav1Fragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_first,container,false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(v -> {
//页面跳转
Navigation.findNavController(view).navigate(R.id.action_FirstFragment_to_SecondFragment);
});
}
}
运行项目,页面就可以实现页面跳转了。
as中直接通过basic Activity创建的页面和上述功能差不多
如果想创建一个带底部导航的,可以用bottom navigation activity 创建
navigation 原理
上课老师总结的,贴上来,方便以后复习
JetPack技术
Navigation基本使用
请参考上课代码
Navigation原理
初始化过程 NavHostFragment生命周期方法
-
1.NavHostFragment的创建
NavHostFragment.create方法
(1)初始化Bundle,并且将graphResId,startDestinationArgs存储在Bundle中。
(2)new NavHostFragment()返回NavHostFragment实例。 -
2.XML文件的解析:主要是解析布局文件的两个属性。defaultNavHost和navGraph,并且初始化全局变量
NavHostFragment.onInflate方法 当Fragment以XML的方式静态加载时,最先会调用onInflate的方法
(调用时机:Fragment所关联的Activity在执行setContentView时) -
3.onCreateNavController方法中
- 在实现导航的时候,我们需要根据navigation配置文件生成NavGraph类,然后在根据每个不同的action id,找到对应的NavDestination就可以实现页面导航跳转了。
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
- 1.其中mNavigatorProvider是NavController中的全局变量,内部通过HashMap键值对的形式保存Navigator类。
- 2.createFragmentNavigator方法,构建了FragmentNavigator对象,其中抽象类Navigator还有个重要的实现类ActivityNavigator和NavGraphNavigator。
这个两个类的对象在NavController的构造方法中被添加。
其中Navigator类的作用是:能够实例化对应的NavDestination,并且能够实现导航功能,拥有自己的回退栈。
- 3.NavHostFragment.onCreate方法。 导航初始化
无论是XML实现还是代码实现,都会执行Fragment的onCreate方法.
NavController在这里被创建,并且NavHostFragment中有一个NavController对象。
(1)初始化NavController,NavController为导航的控制类,核心类。
mNavController = new NavHostController(context);
(2)if (savedInstanceState != null) {开始恢复状态}
(3)if (mGraphId != 0) {设置导航图信息}
- .setGraph()方法
构建NavGraph
在构建NavController的时候,我们还调用了NavController.setGraph(graphId)方法,
该方法主要是构建NavGraph。
(1)调用getNavInflater方法创建NavInflater对象,用于解析navigation xml
- 4. NavInflater.inflate方法
根据传入的XML资源id构建NavGraph,NavGraph组成Fragment路由的导航地图,而NavDestination代表了导航的每一个目的地。在解析完NavDestination后,需要要求NavDestination为NavGraph,即NavGraph是NavDestination的子类。而且在NavGraph内部存储了NavDestination信息。
- 5.上面的inflate方法内部会继续调用inflate方法。
(1)getNavigator方法获取都Navigator实例,该实例在构建NavController是被添加进去,这里获取的是FragmentNavigator对象。
(2)createDestination方法,会调用FragmentNavigator的createDestination构建Destination对象。
(3)onInflate方法,解析destination XML
(4)while循环内部通过递归构建导航图。
- 6.
通过NavInflater类之后,解析了XML文件构建整个Graph之后。,
下面回到setGraph方法,在解析玩XML后会,
回到NavHostFragment.setGraph方法。
(1)popBackStackInternal方法将回退栈中的信息全部出栈。
(2)调用onGraphCreated主要是显示一个导航Fragment视图。
- 7.onGraphCreated方法
(1)恢复之前的导航状态
(2)调用navigate方法,显示第一个Fragment。即在Navigation文件里,属性app:startDestination的Fragment。所以最终都会走到navigate导航方法。
- 4.NavHostFragment.onCreateView方法
该NavHostFragment的视图就只有一个FragmentContainerView extends FrameLayout
containerView.setId(getContainerId());//这行主要用于以代码方式添加fragment - 5.NavHostFragment.onViewCreated
//把mNavController记录在view的tag中
Navigation.setViewNavController(view, mNavController);
获取NavController
- 1.获取NavController
NavHostFragment.findNavController(fragment)
2.findNavController方法 该方法没什么实质性的代码,只要是调用了findViewNavController方法。
3.findViewNavController方法 通过view.tag查找NavController。内部调用了getViewNavController方法。
4.getViewNavController方法 通过获取view的Tag,获取NavController对象,这里的tag ID和setViewNavController都是nav_controller_view_tag。
导航
-
1.在构建和获取到NavController对象以及NavGraph之后。,
下面是使用它来实现真正的导航了。下面从navigate开始分析。在navigate方法内部会查询到NavDestination,然后根据不同的Navigator实现页面导航。
navigate 方法
(1)如果回退栈为null返回NavGraph,不为null返回回退栈中的最后一项。
NavDestination currentNode = mBackStack.isEmpty()
? mGraph
: mBackStack.getLast().getDestination();
(2)根据id,获取对应的NavAction。然后在通过NavAction获取目的地id。
final NavAction navAction = currentNode.getAction(resId);
destId = navAction.getDestinationId();
(4)利用目的地ID属性,通过findDestination方法,找到准备导航的目的地。
NavDestination node = findDestination(destId);
(5)开始导航
1.navigate(node, combinedArgs, navOptions, navigatorExtras);
2.NavDestination newDest = navigator.navigate(node, finalArgs,
navOptions, navigatorExtras); -
2.FragmentNavigator的实现
通过以上的分析,又来到了Navigator 的子类FragmentNavigator类。下面来看看FragmentNavigator.navigate的方法。
(1)调用instantiateFragment,通过反射机制构建Fragment实例
(2)处理进出场等动画逻辑
(3)最终调用FragmentManager来处理导航逻辑。
**ActivityNavigator最终也是调用了startActivity方法,请课后阅读
总结
- (1)NavHostFragment 作为导航载体,在Activity的layout文件里被引用(或者在代码中动态),并且持有导航控制类NavController引用。
(2)NavController 将导航任务委托给Navigator类,Navigator类有两个重要的子类FragmentNavigator和ActivityNavigator子类。NavController类持有NavInflater类引用。
(3)NavInflater 负责解析Navgation文件,负责构建NavGraph导航图。
(4)NavDestination 存有各个目的地信息,在FragmentNavigator和ActivityNavigator内部分别对应一个Destination类,该类继承NavDestination。
(5)在页面导航时,fragment的操作还是交由FragmentManager在操作,activity交由startActivity执行。
思维导图