赞
踩
即学即用Android Jetpack系列Blog的目的是通过学习Android Jetpack完成一个简单的Demo,本文是即学即用Android Jetpack系列Blog的第一篇。
记得去年第一次参加谷歌开发者大会的时候,就被Navigation的图形导航界面给迷住了,一句卧槽就代表了小王的全部心情~,我们可以看一下来自网络的一张图片:
所以,Android Jetpack学习之旅就开始了。
本人打算每周学习一个组件(上图的左上区域),最后将所学的组件组成一个简单的Demo。同时,刚刚过去的2019年谷歌开发者大会宣布亲儿子Kotlin成为开发Android的首选语言,所以本文的Demo也将都会采用Kotlin编写。
本章结束后登录部分完成效果:
语言:KotlinDemo地址:https://github.com/mCyp/Hoo
1. 定义
Navigation是什么呢?谷歌的介绍视频上说:
Navigation是一个可简化Android导航的库和插件
更确切的来说,Navigation是用来管理Fragment的切换,并且可以通过可视化的方式,看见App的交互流程。这完美的契合了Jake Wharton大神单Activity的建议。
2. 优点
3. 准备
如果想要进行下面的学习,你需要 3.2 或者更高的Android studio。
4. 学习方式
最好的学习方式仍然是通过官方文档,下面是官方的学习地址:谷歌官方教程:Navigation Codelab谷歌官方文档:Navigation官方Demo:Demo地址
在实战之前,我们先来了解一下Navigation中最关键的三要素,他们是:
名词解释Navigation Graph(New XML resource)如我们的第一张图所示,这是一个新的资源文件,用户在可视化界面可以看出他能够到达的Destination(用户能够到达的屏幕界面),以及流程关系。NavHostFragment(Layout XML view)当前Fragment的容器NavController(Kotlin/Java object)导航的控制者
可能我这么解释还是有点抽象,做一个不是那么恰当的比喻,我们可以将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导航
除了可视化界面之外,我们仍然有必要看一下里面的内容组成,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标签的属性:
属性解释app:startDestination默认的起始位置
第三步 建立NavHostFragment
我们创建一个新的LoginActivity,在activity_login.xml文件中:
- <androidx.constraintlayout.widget.ConstraintLayout
- ...>
-
- <fragment
- 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"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
有几个属性需要解释一下:
属性解释android:name值必须是androidx.navigation.fragment.NavHostFragment,声明这是一个NavHostFragmentapp:navGraph存放的是第二步建好导航的资源文件,也就是确定了Navigation Graphapp:defaultNavHost="true"与系统的返回按钮相关联
第四步 界面跳转、参数传递和动画
在WelcomeFragment中,点击登录和注册按钮可以分别跳转到LoginFragment和RegisterFragment中。
image
这里我使用了两种方式实现:
方式一 利用ID导航
目标:WelcomeFragment携带key为name的数据跳转到LoginFragment,LoginFragment接收后显示。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将数据传到RegisterFragment,RegisterFragment接收后显示。再看一下已经展示过的login_navigation.xml:
- <navigation
- ...>
-
- <fragment
- ...
- />
-
- <fragment
- android:id="@+id/welcome"
- >
- <action
- android:id="@+id/action_welcome_to_login"
- app:destination="@id/login"/>
- <action
- android:id="@+id/action_welcome_to_register"
- app:enterAnim="@anim/slide_in_right"
- app:exitAnim="@anim/slide_out_left"
- app:popEnterAnim="@anim/slide_in_left"
- app:popExitAnim="@anim/slide_out_right"
- app:destination="@id/register"/>
- </fragment>
-
- <fragment
- android:id="@+id/register"
- ...
- >
-
- <argument
- android:name="EMAIL"
- android:defaultValue="2005@qq.com"
- app:argType="string"/>
- </fragment>
- </navigation>
-
细心的同学可能已经观察到navigation目录下的login_navigation.xml资源文件中的action标签和argument标签,这里需要解释一下:action标签
属性作用app:destination跳转完成到达的fragment的Idapp:popUpTo将fragment从栈中弹出,直到某个Id的fragment
argument标签
属性作用android:name标签名字app:argType标签的类型android:defaultValue默认值
点击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 Args,action可以由Navigation.createNavigateOnClickListener(R.id.next_action, null)方式生成,感兴趣的同学可以自行编写。
Navigation可以绑定menus、drawers和bottom 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)
- }
- }
-
效果:
现在都说互联网寒冬,其实只要自身技术能力够强,咱们就不怕!我这边专门针对Android开发工程师整理了一套【Android进阶学习视频】、【全套Android面试秘籍】、【Android知识点PDF】。如有需要获取资料文档的朋友,可以[点击我的GitHub]免费获取!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。