Navigation是指允许用户在应用程序中浏览、进入和退出不同内容的Fragment。Navigation能够实现从简单的按钮单击到更复杂的模式,如应用程序栏和导航抽屉。导航组件还通过遵循一套既定的原则来确保一致和可预测的用户体验。
来看下Navigation的原则吧:
- 固定的起始位置:也就是说除去登陆等一次性界面,用户在启动App最先看到的界面需要为一个固定的起始界面。
- Navigation的表现形式为堆栈形式:就是Navigation应该类似为栈一样,栈顶为用户所看到的界面,界面的切换总是在栈顶进行,导航到目标后,目标位于栈顶。
- 标题栏的回退应该和返回键的功能一样,但是标题栏不能退出应用:这个也很容易理解,因为两个的定义就存在本质的区别。
- Deep Link:也就是从其他页面,比如浏览器,跳转到App时,用户首先看到的应该还是浏览器的那个页面,没有其他界面的跳转过程。
这些原则,无疑都是为了带给用户良好的体验,也是我们应该遵守的。
Navigation:有三个主要的部分:
- Navigation graph:也就是Navigatation的xml文件,包含所有的需要跳转的目标
- NavHost:一个容器,用于显示
- NavController:控制跳转流程
Google官方也指出了使用Navigation具有以下优点:
- 方便的处理Fragment事务
- 正确的处理标题栏的回退与实体返回键
- 实现过渡动画的统一管理
- 实现并处理Deep Link
- 用最少的工作完成导航栏的UI设计
- Safe Args:在Fragment切换是提供类型安全的数据
- 支持ViewModel
具体实现
新建两个Fragment,HomeFragment和DetailFragment。
在Activity中为Fragment添加NavHost容器。
NavActivity.java
<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/nav" />
再新建navigation文件夹新建Navigation graph。添加Fragment到其中
建立Fragment之间的跳转关系,当然也可以直接在xml文件里写,不过这样会有点麻烦。
nav.xml
<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"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.hao.jetpackdemo.navigation.HomeFragment"
android:label="home"
tools:layout="@layout/home_fragment">
<action
android:id="@+id/action_homeFragment_to_detailFragment2"
app:destination="@id/detailFragment"
app:enterAnim="@anim/nav_default_pop_enter_anim"
app:exitAnim="@anim/nav_default_pop_exit_anim" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.hao.jetpackdemo.navigation.DetailFragment"
android:label="detail"
tools:layout="@layout/fragment_detail">
<action
android:id="@+id/action_detailFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:enterAnim="@anim/nav_default_pop_enter_anim"
app:exitAnim="@anim/nav_default_pop_exit_anim" />
</fragment>
</navigation>
现在便可以来具体实现跳转了。
HomeFragment.java
public class HomeFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.home_fragment, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Objects.requireNonNull(getView()).findViewById(R.id.button)
.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_homeFragment_to_detailFragment2));
}
}
其实createNavigateOnClickListener()
也就是对onClickListener进行了封装,,,怎么说嘞,Jetpack里面对很多对象都进行了进一步的封装,虽然简化了开发的代码量,但是想要弄清原理就更要麻烦点了。
好了,Navigation的初步使用也就到这了
Fragement间数据传递
这里也没有很大的变化,也是通过Bundle来传递的,然后接收方通过getArguments()来获取到对应的Bundle从而取出数据
Fragment转换动画
也是可以直接在Navigation graph中直接设置转换动画,说真的极大减少了工作量。
配合ViewModel、Databinding、LiveData使用
借用https://www.bilibili.com/video/av61814701中的图片
其实和前面的操作也都差不多,只不过两个Fragment共享一个ViewModel。