admin管理员组文章数量:1635839
Jetpack组件系列文章
Android架构之LifeCycle组件
Android架构之Navigation组件(一)
Android架构之Navigation组件(二)
Android架构之Navigation组件(三)
Android架构之Navigation组件(四)
Android架构之ViewModel组件
Android架构之LiveData组件
Android架构之Room组件(一)
Android架构之Room组件(二)
Android架构之WorkManager组件
Android架构之DataBinding(一)
Android架构之DataBinding(二)
Android架构之Paging组件(一)
Android架构之Paging组件(二)
Jetpack与MVVM架构
Navigation介绍
Navigation是Jetpack中的一个组件,支持用户导航、进入和退出应用中不同内容片段的交互,方便我们管理页面和App bar, 它具有以下优势
- 可视化的页面导航图,便于我们理清页面间的关系。
- 通过destination和action完成页面间的导航
- 方便添加页面切换动画
- 页面间类型安全的参数传递
- 通过NavigationUI类,对菜单、底部导航、抽屉菜单导航进行统一的管理
- 支持深层链接DeepLink
看到这里是不是有个疑问? destination和action到底是什么呢?
大部分情况下一个destination就表示一个Fragment,同样也可以表示Activity,或者其它的导航图。 多个destination连接起来就组成了一个导航图。destination之间的连接就叫做action.
Navigation中的主要元素
- Navigation Graph.这是一种新型的XML资源文件,其中包含应用程序所有的页面,以及页面间的关系
- NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示 Fragment 目标。 Navigation Graph中的Fragment正是通过NavHostFragment进行展示的
- NavController:在NavHost中管理应用导航的对象,用于在代码中完成Navigation Graph中具体的页面切换工作。
3种元素之间的关系:
当你想切换Fragment时,使用NavController对象,告诉它你想要去NavigationGraph中的哪个Fragment, NavController会将你想去的Fragment展示在NavHostFragment;
Navigation基本使用
添加依赖
implementation 'androidx.navigation:navigation-fragment:2.3.1'
implementation 'androidx.navigation:navigation-ui:2.3.1'
创建资源文件
选择res文件夹->New->Android Resource File, 新建一个Navigation Graph文件. 如下图所示: 将File name 设置为 nav_graph, Resource type设置为Navigation
在Activity添加NavHostFragment
NavHostFragment是一个特殊的Fragment,我们需要将其添加到Activity的布局文件中,作为其他Fragment的容器
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
xmlns:app="http://schemas.android/apk/res-auto"
xmlns:tools="http://schemas.android/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:defaultNavHost= "true"
app:navGraph="@navigation/nav_graph"/>
</LinearLayout>
- android:name 是NavHostFragment,它实现了NavHost,这是一个用于放置管理destination的空视图
- app:navGraph: 用于将这个NavHostFragment和nav_graph.xml关联起来
- app:defaultNavHost:设置为true,则该Fragment会自动处理系统返回键即当用户按下手机的返回按钮时,系统能自动将当前所展示的Fragment退出
创建destination
回到nav_graph.xml中,依次单机加号按钮、"Create new destination"按钮,创建一个destination
destination是"目的地"的意思,代表着你想去的页面,它可以是Fragment或Activity. 我们通过destination 创建一个名为MainFragment的Fragment,
创建完之后 如下图所示
面板中出现了一个mainFragment. "Start"表示该MainFragment是起始Fragment, 即NavHostFragment容器首先展示的Fragment
接着查看 nav_graph.xml文件,发现多出了一个fragment标签
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android/apk/res/android"
xmlns:app="http://schemas.android/apk/res-auto"
xmlns:tools="http://schemas.android/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.jetpack.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
</fragment>
</navigation>
可以看到,在navigation标签下有一个startDestination属性,该属性指定起始destination为mainFragment
运行程序,即可以看到一个Fragment,即destination所指定的mainFragment
完成Fragment页面切换
与创建MainFragment的方式类似,先创建一个SecondFragment
单击mainFragment,用鼠标选中其右侧的圆圈,并拖拽至右边的secondFragmen
在nav_graph.xml文件中,发现mainFragment多出了一个标签
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android/apk/res/android"
xmlns:app="http://schemas.android/apk/res-auto"
xmlns:tools="http://schemas.android/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.jetpack.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_mainFragment_to_secondFragment2"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.jetpack.secondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
</navigation>
app:destination: 指定要跳转到的Fragment的id
app:id 定义这个action的id, 代码里执行跳转时要用到
使用NavController 完成导航
跳转通过 NavController 对象,它有三种获取方法:
- NavHostFragment.findNavController(Fragment)
- Navigation.findNavController(Activity, @IdRes int viewId)
- Navigation.findNavController(View)
回到MainFragment的布局文件中 添加一个Button
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android/apk/res/android"
xmlns:tools="http://schemas.android/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_blank_fragment" />
<Button
android:id="@+id/btntoSecondFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="to SecondFragment"
android:layout_below="@id/tv_text"
/>
</RelativeLayout>
打开MainFragment,响应这个按钮的单击事件,完成具体的页面切换
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main,container,false);
//方法一
view.findViewById(R.id.btntoSecondFragment).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(v)
.navigate(R.id.action_mainFragment_to_secondFragment);
}
});
//方法二
view.findViewById(R.id.btntoSecondFragment).setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.action_mainFragment_to_secondFragment)
);
return view;
}
调用 NavController 的 navigate 方法执行跳转,navigate 的参数可以是一个 destination(这里就是 fragment 在导航图 nav_graph 中的 id),也可以是 action 的 id。
当点击按钮的时候,跳转到了secondFragment
这里可以看到Fragment完成了切换,但切换没有动画效果,显得很生硬。
添加页面切换动画效果
点击目标箭头,并在右边的Animations面板中为其设置动画文件
代码自动变成
<fragment
android:id="@+id/mainFragment"
android:name="com.example.jetpack.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_mainFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:enterAnim="@android:anim/slide_out_right"
app:exitAnim="@android:anim/slide_in_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right" />
</fragment>
enterAnim和exitAnim是去往栈里添加一个destination时动画,popEnterAnim和popExitAnim是从栈里移除一个destination时的动画
运行程序,此时切换页面便可以看到动画效果。
传递参数
定义目的地参数
如需在目的地之间传递数据,首先请按照以下步骤将参数添加到接收它的目的地来定义参数:
- 在 Navigation Editor 中,点击接收参数的目的地。 在 Attributes 面板中,点击 Add (+)。
- 在显示的 Add Argument Link 窗口中,输入参数名称、参数类型、参数是否可为 null,以及默认值(如果需要)。
- 点击 Add。请注意,该参数现在会显示在 Attributes 面板的 Arguments 列表中。
- 接下来,点击会将您转到此目的地的相应操作。在 Attributes 面板中,您现在应该会在 Argument DefaultValues 部分中看到新添加的参数。
- 您还可以看到该参数已添加到 XML 中。点击 Text 标签页以切换到 XML 视图,就会发现您的参数已添加到接收该参数的目的地。相关示例如下所示:
<fragment android:id="@+id/myFragment" >
<argument
android:name="age"
app:argType="integer"
android:defaultValue="0" />
</fragment>
支持的参数类型
使用Safe Args传递安全的数据
Navigation 组件具有一个名为 Safe Args 的 Gradle 插件,该插件可以生成简单的 object 和 builder 类,以便以类型安全的方式浏览和访问任何关联的参数
在项目的build.gradler文件中添加safe args插件
dependencies {
def nav_version = "2.3.0-alpha05"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
在app的build.gradle文件中添加对safe args的依赖
apply plugin: "androidx.navigation.safeargs"
在导航图添加标签
可以直接在Text中编写,也可以通过Design面板进行添加
<fragment
android:id="@+id/mainFragment"
android:name="com.example.jetpack.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_mainFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:enterAnim="@android:anim/slide_out_right"
app:exitAnim="@android:anim/slide_in_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right" />
<!--添加参数-->
<argument
android:name="user_nmae"
app:argType="string"
android:defaultValue="unknown"
/>
<argument
android:name="age"
app:argType="integer"
android:defaultValue="0"
/>
</fragment>
- android:name 是传递参数的名称
- app:argType 是传递参数的类型
- android:defaultValue: 是传递参数的默认值,需要根据app:argType进行添加
添加,对项目进行编译,便可以在app/generatedJava目录下看到safe args插件为我们生成的代码文件了.在这些代码文件中包含了参数所对应的Getter 和Setter方法
最后利用生成的代码文件,进行Fragment之间进行参数传递
使用 Bundle 对象在目的地之间传递参数
在MainFragment进行参数传递
view.findViewById(R.id.btntoSecondFragment).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new MainFragmentArgs.Builder().
setUserNmae("Shaoyi")
.setAge(20)
.build().toBundle();
Navigation.findNavController(v)
.navigate(R.id.action_mainFragment_to_secondFragment,bundle);
}
});
参数接收
在secondFragment进行参数接收
Bundle bundle = getArguments();
if(bundle!=null){
String userName = MainFragmentArgs.fromBundle(bundle).getUserNmae();
int age = MainFragmentArgs.fromBundle(bundle).getAge();
Toast.makeText(getActivity(), "名字为"+userName+"年龄为"+age, Toast.LENGTH_SHORT).show();
}
运行结果如下
正如插件safe args名字所代表的意思,它的主要好处在于安全的参数类型。Getter和Setter的方式令参数的操作更友好,更直观,且更安全。
不用action进行切换页面 不用safe args传递参数
编写nav_graph.xml文件
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android/apk/res/android"
xmlns:app="http://schemas.android/apk/res-auto"
xmlns:tools="http://schemas.android/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.jetpack.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.jetpack.secondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
</navigation>
mainFragment中的代码
传递参数
Bundle bundle = new Bundle();
bundle.putString("user_name","shaoyi");
bundle.putInt("")
Navigation.findNavController(v)
.navigate(R.id.secondFragment,bundle);
只需要将navigate()方法中的id改成其他的Fragment的id即可(原先是action的id),但是需要注意的是,该Fragment必须要在nav_graph.xml进行注册.
而且参数传递 也可以不用标签,也就是不使用Safe Args插件,直接使用Bundle对象在目的地之间进行传递。
secondFragment中的代码
接收参数
Bundle bundle = getArguments();
if(bundle!=null){
String userName = bundle.getString("user_name");
int age = bundle.getInt("age");
Toast.makeText(getActivity(), "名字为"+userName+"年龄为"+age, Toast.LENGTH_SHORT).show();
}
参考:
- https://developer.android.google/guide/navigation/navigation-pass-data
- Android Jetpack 应用指南
本文标签: 架构组件androidnavigation
版权声明:本文标题:Android架构之Navigation组件(一) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1729217407a1190581.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论