DataBinding/ViewBinding和Navigation的源码分析在我看来价值不大,这里只是做一些使用的说明。

DataBinding/ViewBinding

1.什么是DataBinding,什么是ViewBinding?两者有什么区别

还记得被findViewById支配的恐惧吗 在还在用 java的时候 每次编写Activity的时候都需要用大量代码量去findViewById 到后来出现了黄油刀Butterknife 但是依旧需要去声明变量;然后到了kotlin第一次接触kotlin-android-extensions插件 卧槽这玩意也太香了吧 然而用着用着 这玩意就被弃用了,之后黄油刀Butterknife也被废弃了。之后就被viewbinding替代了,然后由于viewbing引入会拖垮编译速度,之后又加入了databinding。

ViewBinding 相当于是 DataBinding 的阉割版 只是做到了能够快速简单的获得布局中的View 也就是视图绑定; 而 DataBinding 可以做到数据绑定 也就是view和数据的双向绑定,但是目前它的双向绑定有坑,我的建议是不要用,这里也不会去介绍它的数据绑定,感兴趣可自行查阅。

2.简单使用

先讲viewbinding

首先在build.gradle中加入:

android{
.....
viewBinding{
enabled = true
}
}

然后sysnc一下项目,之后在activtiy中去获取viewbinding的实例:

class MainActivity : AppCompatActivity() {

private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.button.setOnClickListener {

}

}

系统会根据的xml布局文件名字生成一个Binding类,比如我们的MainActivity生成的viewbinding类就是ActivityMainBinding,这里就是通过懒加载去ActivityMainBinding.inflate(layoutInflater)渲染布局,接下来setContentView(mBinding.root)的参数view也改为binding.root,然后就可以直接用你的binding去获取的view,view的名字就是他的id:

这样我们就少去了findviewbyId 的流程,而是直接用view的id。

databinding的使用方法略有不同,手先在build.gradle中:

android{
.....
buildFeatures {
dataBinding true
}
}

sysnc一下,然后xml需要改成databinding 的形式系统才会给你生成对应的类,快捷方法是点击顶部的标签,Alt+Enter快捷键:

选择第一个Convert to databinding layout,就变成这个样子了:

之后在代码中获取的方式就和viewbinding一样了。

总结:

1.引入依赖

2.如果是databinding则要将xml改成databinding的形式

3.用系统生成的Binding类去inflate渲染布局

4.binding.root替代渲染的view

在recyclerview中的用法和这里差不多,这里不多说了,在这之后文章里用的都是viewBinding。

Navigation

1.什么是Navigation?

翻译过来就是导航,应用官方的话就是说:

导航是指支持用户导航、进入和退出应用中不同内容片段的交互。Android Jetpack 的导航组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。导航组件还通过遵循一套既定原则来确保一致且可预测的用户体验。

简单来说就是负责页面之间的跳转的。

2.为什么需要Navigation?

导航组件提供各种其他优势,包括以下内容:

  • 处理 Fragment 事务。
  • 默认情况下,正确处理往返操作。
  • 为动画和转换提供标准化资源。
  • 实现和处理深层链接。
  • 包括导航界面模式(例如抽屉式导航栏和底部导航),用户只需完成极少的额外工作。
  • Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。
  • ViewModel 支持 - 您可以将 ViewModel 的范围限定为导航图,以在图表的目标之间共享与界面相关的数据。

3.如何使用?

首先是导入依赖:

// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"
implementation "androidx.navigation:navigation-ui-ktx:2.5.3"

然后我们在开始前先了解一下Navigation由哪几部分组成:

Naviagation由以下三个关键部分组成:

  • 导航图(NavGraph):在一个集中位置包含所有导航相关信息的 XML 资源。这包括应用内所有单个内容区域(称为目标)以及用户可以通过应用获取的可能路径。
  • NavHost:显示导航图中目标的空白容器。导航组件包含一个默认 NavHost 实现 (NavHostFragment),可显示 Fragment 目标。
  • NavController:在 NavHost 中管理应用导航的对象。当用户在整个应用中移动时,NavController 会安排 NavHost 中目标内容的交换。

首先是导航图:

我这里创建了两个Fragment:

然后创建导航图,导航图怎么创建呢?右键resource–>new—->Android Resource File,然后输入文件名称,名字可以自己取,然后Resource Type选择Navigation:

创建好了之后你的文件就在res–>navigation文件夹下,然后我们打开,切换到desigin:

点击左上角像页面一样的图标:

这里就可以选择你要添加的activity或者Fragment页面:

添加好图片之后,就可以拖动页面右边的小圆点指向SecondFragment,就表示从FirstFragment跳转到SecondFragment,我这里简单做了两个跳转:

然后你会发现xml给我们生成这么些代码:

<?xml version="1.0" encoding="utf-8"?>
<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/navi_graph"
app:startDestination="@id/firstFragment">

<fragment
android:id="@+id/firstFragment"
android:name="com.wssg.androidteach.fragment.FirstFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" >
<action
android:id="@+id/action_firstFragment_to_secondFragment3"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.wssg.androidteach.fragment.SecondFragment"
android:label="SecondFragment" >
<action
android:id="@+id/action_secondFragment_to_firstFragment"
app:destination="@id/firstFragment" />
</fragment>
</navigation>

这就是NaviGraph的代码,startDestination就是一开始的页面,然后一个Fragment标签或者activity标签就是一个页面,name必须是你Fragment或者activity的包名,然后就是action,一个action就是一个跳转,所以一个Fragment可以有多个跳转,在用NaviController跳转的时候指定action的id来实现一个跳转,destination就是目的地嘛,顾名思义就是要跳转到的页面。

好,NaviGraph有了,现在是NaviHost,在activity的xml布局中点击右上角的搜索符号,搜索NavHost:

然后将那个NavHostFragment拖到activity页面里面,NavHost就添加成功了:

之后你会在xml发现生成了这样的代码:

<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="409dp"
android:layout_height="261dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:navGraph="@navigation/navi_graph" />

name必须是NavHostFragment,defaultNavHost设置为true,再指定navGraph为我们的写的navi_graph。

好,现在NavHost有了,再在代码中用NavController去控制跳转:

class FirstFragment : Fragment() {
private val mBinding by lazy { FragmentFirstBinding.inflate(layoutInflater) }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return mBinding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
mBinding.button.setOnClickListener {
findNavController().navigate(
R.id.action_firstFragment_to_secondFragment,
Bundle().apply { putString("data", "我传了个数据") })
}
}
}

跳转代码就是:

findNavController().navigate(R.id.action_firstFragment_to_secondFragment,Bundle().apply { putString("data", "我传了个数据") })

这是你要传参数的情况,不传参数你就直接去掉bundle就行了:

findNavController().navigate(R.id.action_firstFragment_to_secondFragment)

在SecondeFragment里面也是如此,不过是执行action的id不同:

class SecondFragment : Fragment() {

private val mBinding by lazy { FragmentSecondBinding.inflate(layoutInflater) }

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return mBinding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val string = arguments?.getString("data")//你如果用bundle传了参数就这样获取
mBinding.textView3.text = string
mBinding.button.setOnClickListener {
findNavController().navigate(R.id.action_secondFragment_to_firstFragment)
}
}
}

这样我们navigation就可以完美运行了。传参数的话官方有个Safe Args插件,可以保证类型安全,但是我觉得用起来很麻烦,这种原生传参我觉得更好一些,感兴趣的可以自己查阅一下,这里就不介绍了。

加入你需要跳转动画的话,打开你的NavGraph:

在右侧有Animators一栏,在这里用@引用你的动画文件,我这里是用的系统默认的动画,enter/exitAnim是进入/结束动画,popEnter/popExitAnim是弹入弹出动画。

动画是加在action里面的,你也可以手动码代码:

<fragment
android:id="@+id/firstFragment"
android:name="com.wssg.androidteach.fragment.FirstFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim" />
</fragment>

Navigation的用法差不多就是这些了,接下来我讲个比较常用的NavigationUI吧,就是很常用的底部导航栏——BottomNavigationView:

BottomNavigationView

BottomNavigationView就是官方的底部导航栏。我们看看怎么使用

首先我们需要创建一个menu,右键res,选择Android Resource File,名字自取,然后编写这样的代码:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/bottom_nav_home"
android:icon="@drawable/home"
android:title="首页" />
<item
android:id="@+id/bottom_nav_marketplace"
android:icon="@drawable/find"
android:title="广场" />
<item
android:id="@+id/bottom_nav_wechat"
android:icon="@drawable/wechat"
android:title="公众号" />
<item
android:id="@+id/bottom_nav_system"
android:icon="@drawable/system"
android:title="体系" />
<item
android:id="@+id/bottom_nav_project"
android:icon="@drawable/project"
android:title="项目" />
</menu>

一个item就底部导航栏的一个按钮,icon是按钮的图片,title是按钮的文字。

然后将我们的theme改成:

<style name="Theme.WanAndroid" parent="Theme.MaterialComponents.DayNight.NoActionBar">

不然BottomNavgationView背景会变黑,然后再activtiy加入bottomNavigationView:

注意:BottomNavigationView规定,底部按钮不能超过5个,否则会抛出异常。

指定menu文件,然后在代码中设置按钮监听:

mBinding.bottomNav.setOnItemSelectedListener {
when (it.itemId) {
R.id.bottom_nav_home -> {
//
}
R.id.bottom_nav_project -> {

}
R.id.bottom_nav_system -> {

}
R.id.bottom_nav_marketplace -> {

}
R.id.bottom_nav_wechat -> {

}
}
return@setOnItemSelectedListener true
}

这里就是用id来判断你点中的是menu里面的哪个按钮,我们一般会搭配viewpager+fragment这也是市面上大多数的app页面设计,搭配viewpager+fragment就是:

mBinding.bottomNav.setOnItemSelectedListener {
when (it.itemId) {
R.id.bottom_nav_home -> binding.viewPager.currentItem = 0
R.id.bottom_nav_marketplace -> binding.viewPager.currentItem = 1
R.id.bottom_nav_wechat -> binding.viewPager.currentItem = 2
R.id.bottom_nav_system -> binding.viewPager.currentItem = 3
R.id.bottom_nav_project -> binding.viewPager.currentItem = 4
}
return@setOnItemSelectedListener true
}

viewpager2+fragment就不多说了,你们应该都会,这里其实就是点击底部按钮,然后将viewpager2翻至对应的页面。

简单的用法就是这样,还有更多的用法这里说不完了,比如NavigationUI里还有侧滑栏DrawerLayout和顶部导航栏,都是可以和BottomNavigationIView联动的,但是用的不多,感兴趣可自行查阅。BottomNavigationIView还有很多属性,比如说影藏文字,更改选中的颜色等等等等,这里篇幅不够,大家自行挖掘吧。