注册

即学即用Android Jetpack - Navigation

前言


即学即用Android Jetpack系列Blog的目的是通过学习Android Jetpack完成一个简单的Demo,本文是即学即用Android Jetpack系列Blog的第一篇。


记得去年第一次参加谷歌开发者大会的时候,就被Navigation的图形导航界面给迷住了,一句卧槽就代表了小王的全部心情~


目录


一、简介


1. 定义


Navigation是什么呢?谷歌的介绍视频上说:



Navigation是一个可简化Android导航的库和插件



更确切的来说,Navigation是用来管理Fragment的切换,并且可以通过可视化的方式,看见App的交互流程。这完美的契合了Jake Wharton大神单Activity的建议。


2. 优点



  • 处理Fragment的切换(上文已说过)
  • 默认情况下正确处理Fragment的前进和后退
  • 为过渡和动画提供标准化的资源
  • 实现和处理深层连接
  • 可以绑定ToolbarBottomNavigationViewActionBar

  • SafeArgs(Gradle插件) 数据传递时提供类型安全性

  • ViewModel支持

3. 准备


如果想要进行下面的学习,你需要 3.2 或者更高的Android studio


4. 学习方式


最好的学习方式仍然是通过官方文档,下面是官方的学习地址:

谷歌官方教程:Navigation Codelab

谷歌官方文档:Navigation

官方Demo:Demo地址


二、实战

可能我这么解释还是有点抽象,做一个不是那么恰当的比喻,我们可以将Navigation Graph看作一个地图,NavHostFragment看作一个车,以及把NavController看作车中的方向盘,Navigation Graph中可以看出各个地点(Destination)和通往各个地点的路径,NavHostFragment可以到达地图中的各个目的地,但是决定到什么目的地还是方向盘NavController,虽然它取决于开车人(用户)。



第一步 添加依赖


模块层的build.gradle文件需要添加:

ext.navigationVersion = "2.0.0"
dependencies {
//...
implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
}

如果你要使用SafeArgs插件,还要在项目目录下的build.gradle文件添加:

buildscript {
ext.navigationVersion = "2.0.0"
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
}
}

以及模块下面的build.gradle文件添加:

apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs'

第二步 创建navigation导航



  1. 创建基础目录:资源文件res目录下创建navigation目录 -> 右击navigation目录New一个Navigation resource file

  2. 创建一个Destination,如果说navigation是我们的导航工具,Destination是我们的目的地,在此之前,我已经写好了一个WelcomeFragmentLoginFragmentRegisterFragment

除了可视化界面之外,我们仍然有必要看一下里面的内容组成,login_navigation.xml

<navigation
...
android:id="@+id/login_navigation"
app:startDestination="@id/welcome">

<fragment
android:id="@+id/login"
android:name="com.joe.jetpackdemo.ui.fragment.login.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login"
/>

<fragment
android:id="@+id/welcome"
android:name="com.joe.jetpackdemo.ui.fragment.login.WelcomeFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_welcome">
<action
.../>
<action
.../>
</fragment>

<fragment
android:id="@+id/register"
android:name="com.joe.jetpackdemo.ui.fragment.login.RegisterFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_register"
>

<argument
.../>
</fragment>
</navigation>



我在这里省略了一些不必要的代码


第三步 建立NavHostFragment


我们创建一个新的LoginActivity,在activity_login.xml文件中:

    ...>

android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/login_navigation"
app:defaultNavHost="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>







第四步 界面跳转、参数传递和动画

WelcomeFragment中,点击登录和注册按钮可以分别跳转到LoginFragmentRegisterFragment中。

这里我使用了两种方式实现:


方式一 利用ID导航

目标:WelcomeFragment携带keyname的数据跳转到LoginFragmentLoginFragment接收后显示。

Have a account ? Login按钮的点击事件如下:

btnLogin.setOnClickListener {
// 设置动画参数
val navOption = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
// 参数设置
val bundle = Bundle()
bundle.putString("name","TeaOf")
findNavController().navigate(R.id.login, bundle,navOption)
}

后续LoginFragment的接收代码比较简单,直接获取Fragment中的Bundle即可,这里不再出示代码。

方式二 利用Safe Args

目标:WelcomeFragment通过Safe Args将数据传到RegisterFragmentRegisterFragment接收后显示。

再看一下已经展示过的login_navigation.xml

<navigation
...
android:id="@+id/login_navigation"
app:startDestination="@id/welcome">

<fragment
android:id="@+id/login"
android:name="com.joe.jetpackdemo.ui.fragment.login.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login"
/>

<fragment
android:id="@+id/welcome"
android:name="com.joe.jetpackdemo.ui.fragment.login.WelcomeFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_welcome">
<action
.../>
<action
.../>
</fragment>

<fragment
android:id="@+id/register"
android:name="com.joe.jetpackdemo.ui.fragment.login.RegisterFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_register"
>

<argument
.../>
</fragment>
</navigation>



细心的同学可能已经观察到navigation目录下的login_navigation.xml资源文件中的action标签和argument标签,这里需要解释一下:
点击Android studio中的Make Project按钮,可以发现系统为我们生成了两个类



WelcomeFragment中的JOIN US按钮点击事件:
btnRegister.setOnClickListener {
val action = WelcomeFragmentDirections
.actionWelcomeToRegister()
.setEMAIL("TeaOf1995@Gamil.com")
findNavController().navigate(action)
}

RegisterFragment中的接收:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// ...
val safeArgs:RegisterFragmentArgs by navArgs()
val email = safeArgs.email
mEmailEt.setText(email)
}
需要提及的是,如果不用Safe Argsaction可以由Navigation.createNavigateOnClickListener(R.id.next_action, null)方式生成,感兴趣的同学可以自行编写。


三、更多


Navigation可以绑定menusdrawersbottom navigation,这里我们以bottom navigation为例,我先在navigation目录下新创建了main_navigation.xml,接着新建了MainActivity,下面则是activity_main.xml:

<LinearLayout
...>

<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
app:navGraph="@navigation/main_navigation"
app:defaultNavHost="true"
android:layout_height="0dp"
android:layout_weight="1"/>

<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:itemIconTint="@color/colorAccent"
app:itemTextColor="@color/colorPrimary"
app:menu="@menu/menu_main"/>

</LinearLayout>



MainActivity中的处理也十分简单:

class MainActivity : AppCompatActivity() {

lateinit var bottomNavigationView: BottomNavigationView

override fun onCreate(savedInstanceState: Bundle?) {
//...
val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
val navController = host.navController
initWidget()
initBottomNavigationView(bottomNavigationView,navController)
}

private fun initBottomNavigationView(bottomNavigationView: BottomNavigationView, navController: NavController) {
bottomNavigationView.setupWithNavController(navController)
}

private fun initWidget() {
bottomNavigationView = findViewById(R.id.navigation_view)
}
}


作者:九心_
链接:https://www.jianshu.com/p/66b93df4b7a6
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1 个评论

很新的技术,正在学习.

要回复文章请先登录注册