本文地址:https://blog.csdn.net/qq_40785165/article/details/113484751,转载需附上此地址
大家好,我是小黑,一个还没秃头的程序员~~~
水再浑浊,只要长久沉淀,依然会分外清澈;人再愚钝,只要足够努力,一样能改写命运。
这次小黑带来的是Android Jetpack中的导航组件-----Navigation,引用官方的一段话介绍导航组件
在不同屏幕和应用之间导航是用户体验的核心组成部分。以下原则为跨各种应用提供一致且直观的用户体验设定了基准。Navigation 组件设计为默认实现这些原则,从而确保用户在各应用之间切换时能够使用相同的启发法和模式进行导航。
注:如果要使用导航和 Android Studio,则必须使用 Android Studio 3.3 或更高版本。
这次文章的内容是Navigation组件的入门使用,使用Kotlin编写,进行简单的Fragment与Fragment/Activity的页面跳转,源码地址:https://gitee.com/fjjxxy/navigation-demo.git,效果图如下
注意事项一:AndroidStudio更新到4.1版本之后kotlin不能再直接用id进行操作控件了,可以改用ViewBinding或者在build(app)中手动添加kotlin-android-extensions插件id
话不多说,正文开始
(一)添加相关依赖,官方版本是2.3.2,但是这个版本下找不到FragmentContainerView,原因未知,所以这里就改用版本2.3.0
def nav_version = "2.3.0"
// 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:1.0.0-alpha05"
(二)准备多个用来切换的Fragment,本案例中有两个Fragment
NavigationFragment1.kt以及fragment_navigation1.xml代码如下:第四行是Fragment跳转Activity的代码,继续往下看就会看到相关内容了
class NavigationFragment1 : BaseFragment() {
override fun initView(rootView: View) {
rootView.tv_to_second.setOnClickListener {
findNavController().navigate(R.id.to_second)
}
}
override fun getLayoutId(): Int {
return R.layout.fragment_navigation1
}
}
NavigationFragment2.kt以及fragment_navigation2.xml代码如下:
class NavigationFragment2 : BaseFragment() {
override fun initView(rootView: View) {
}
override fun getLayoutId(): Int {
return R.layout.fragment_navigation2
}
}
公共类BaseFragment.kt代码如下:只是一个抽象类,方便开发者加载布局和初始化布局
abstract class BaseFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var inflate = inflater.inflate(getLayoutId(), container, false)
initView(inflate)
return inflate;
}
abstract fun initView(rootView: View)
abstract fun getLayoutId(): Int
}
(三)碎片(Fragment)准备好了,现在应该找个容器来装了,就写在MainActivity里,布局文件为activity_main.xml,以往我们的做法是准备一个FrameLayout进行replace替换fragment,这里官方的建议控件是
androidx.fragment.app.FragmentContainerView
activity_main.xml代码如下:布局很简单,FragmentContainerView用来存放不同的Fragment,底下两个TextView用来处理切换Fragment的逻辑
注意事项二:这里FragmentContainerView在指定了name属性后一定要添加id属性,否则会报错
nav_config.xml代码如下:action设置跳转的id以及目的地
注意事项三:startDestination属性不能不写,否则会报错,页面的id也不能不写,否则也会报错
配置文件写完后可以在右方打开Design模式看见导航图,如下图
最后,在MainActivity.kt中实现点击切换Fragment的逻辑,代码如下:
注意事项四:这里需要判断当前fragment是不是没变,没变就不跳转,因为navigation不运行当前页面和目标页面都是自己,否则会报错
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//这里需要判断当前fragment是不是没变,没变就不跳转,因为navigation不运行当前页面和目标页面都是自己,否则会报错
tv_to_fragment1.setOnClickListener {
if (getFragment(NavigationFragment1::class.java) == null) {
findNavController(R.id.fragment_container_view).navigate(R.id.to_fragment1)
}
}
tv_to_fragment2.setOnClickListener {
if (getFragment(NavigationFragment2::class.java) == null) {
findNavController(R.id.fragment_container_view).navigate(R.id.to_fragment2)
}
}
}
@Suppress("UNCHECKED_CAST")
fun AppCompatActivity.getFragment(fragmentClass: Class): F? {
val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment
navHostFragment.childFragmentManager.fragments.forEach {
if (fragmentClass.isAssignableFrom(it.javaClass)) {
return it as F
}
}
return null
}
}
在Activity中导航到目的地有两种方法,我用的第一种
接着调用navigate函数进行导航到目标
NavigationFragment1.kt文件中实现了 Fragment跳转另外一个Activity的代码:同样是通过指定目标的id进行跳转,目标Activity的id和类名称已在上面的nav_config.xml文件中定义于
class NavigationFragment1 : BaseFragment() {
override fun initView(rootView: View) {
tv_to_second.setOnClickListener {
findNavController().navigate(R.id.tv_to_second)
}
}
override fun getLayoutId(): Int {
return R.layout.fragment_navigation1
}
}
- 设计Fragment布局
- 设计存放NavHostFragment的布局,比如这里的activity_main.xml
- 设计navigation的xml配置文件,设置各个目标Fragment/Activity的ID以及类名称
- 在逻辑代码中实现导航到目标的逻辑
- *上面内容提到的不能不写的属性要注意
目前为止,Navigation关于Fragment与Fragment/Activity页面跳转的内容就已经完成了,这篇文章是Navigation系列的入门使用记录,后面我将会带来关于Navigation其他的使用内容,敬请期待,也希望喜欢我文章朋友们可以帮忙点赞、收藏、评论,也可以关注一下,如果有问题可以在评论区提出,也欢迎大家订阅我的个人微信公众号,谢谢大家的支持!