一、 项目准备
1. 引入DataBinding
- 在项目 build.gradle 文件 android 节点下添加
buildFeatures {
dataBinding = true // for data binding
}
2. 引入一个MVVM 框架
implementation 'com.github.AranAndroid009:CustomView:0ca395ae60'
implementation 'com.github.AranAndroid009:Mvvm:97b52ee25b'
3. 引入一个图片浏览的框架 ImageSelector:
注: 该框架模仿微信UI 可以兼容android 10
项目地址: https://github.com/donkingliang/ImageSelector
根据项目文档,自己行导入 做好准备工作
implementation 'com.github.donkingliang:ImageSelector:2.2.1'
4. 引入一个图片加载的框架 Glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
二、 搭一个页面
1. 创建 一个空的Activity
2. 创建 ViewModel
class MainVM : BaseViewModel() {
}
3. 修改XML
- 布局最外层用 layout 节点包裹 , 此时会自动生成 ActivityMainBinding
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
</layout>
- 添加数据绑定, 让改页面拥有MainVM 的一个实例化对象
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="vm"
type="com.winspread.waterrecord.main.MainVM" />
</data>
</layout>
- 我们给页面添加 一个图片控件和按钮控件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="vm"
type="com.winspread.waterrecord.main.MainVM" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:id="@+id/btn_single"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="按钮"/>
</RelativeLayout>
</layout>
3. 修改 Activity
class MainActivity : BaseActivity<MainVM, ActivityMainBinding>(R.layout.activity_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 让页面vm 获取 MainVM 的实例
binding.vm = viewModel
// 绑定activity生命周期, 如果不绑定可能会出现数据改变页面不变的情况
binding.lifecycleOwner = this
}
}
三、 编写逻辑
1. 先写个小功能, 点击按钮, 让按钮文字修改
1.binding.lifecycleOwner = this 上面如果没有写这句绑定会出现点击没有反应
2.btnText 其实变量可以理解为被观察对象,页面去订阅了他改变的事件
- 在 MainVM 定义个变量和方法
var btnText = MediatorLiveData<String>()
fun btnLogin(v: View) {
btnText.value = "点击了"
}
- 将数据和事件绑定到页面上
<Button
android:id="@+id/btn_single"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:onClick="@{(v)->vm.btnLogin(v)}"
android:text="@{vm.btnText}" />
2. 默认是加载一个网络图片, 点击按钮选择一张本地图片
- 根据 ImageSelector 项目开发文档 自行导入, 别忘了添加必要的权限
- 完整 MainVM
class MainVM : BaseViewModel() {
var btnText = MediatorLiveData<String>()
var url = MediatorLiveData<String>()
var uri = MediatorLiveData<Uri>()
var onClick = MediatorLiveData<String>()
// 方式一
fun btnLogin(v: View) {
// btnText.value = "点击了"
onClick.postValue("")
}
}
- 完整 MainActivity
class MainActivity : BaseActivity<MainVM, ActivityMainBinding>(R.layout.activity_main) {
val REQUEST_CODE = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.vm = viewModel
binding.lifecycleOwner = this
initView()
}
private fun initView() {
// 默认显示一个网路图片
viewModel.url.value = "https://t7.baidu.com/it/u=4162611394,4275913936&fm=193&f=GIF"
ImageSelector.preload(this)
// 方式一
viewModel.onClick.observe(this, Observer {
ImageSelector
.builder()
.useCamera(true) // 设置是否使用拍照
.setSingle(true) //设置是否单选
.canPreview(true) //是否可以预览图片,默认为true
.start(this, REQUEST_CODE); // 打开相册
})
// 方式二
binding.btnSingle.setOnClickListener({
ImageSelector
.builder()
.useCamera(false) // 设置是否使用拍照
.setSingle(true) //设置是否单选
.canPreview(true) //是否可以预览图片,默认为true
.start(this, REQUEST_CODE); // 打开相册
})
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE && data != null) {
//获取选择器返回的数据
val images: ArrayList<String>? =
data.getStringArrayListExtra(ImageSelector.SELECT_RESULT)
viewModel.btnText.value = images?.get(0)
viewModel.uri.value = UriUtils.getImageContentUri(this, images?.get(0))
}
}
}
- 完整的XML ( 如果使用方式一 需要添加onClick属性 如果使用方式二 请删掉onClick 这行 )
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="vm"
type="com.winspread.waterrecord.main.MainVM" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<ImageView
android:id="@+id/iv"
imageUri="@{vm.uri}"
imageUrl="@{vm.url}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<!-- 如果使用方式一 需要添加onClick属性
如果使用方式二 请删掉onClick 这行 -->
<Button
android:id="@+id/btn_single"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:onClick="@{(v)->vm.btnLogin(v)}"
android:text="@{vm.btnText}" />
</RelativeLayout>
</layout>
- 完整的 自定义属性
@BindingAdapter("imageUrl")
fun imageUrl(view: ImageView, url: String?) {
url?.let {
Glide.with(view.context)
.load(url)
.into(view)
}
}
@BindingAdapter("imageUri")
fun imageUri(view: ImageView, uri: Uri?) {
uri?.let {
Glide.with(view.context)
.load(uri)
.into(view)
}
}
- 千万别忘了添加插件 (后两个) 否则 BindingAdapter 会报错的
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
}
四 总结关键点(自定义属性)
- 通过DataBinding 自定义属性 完成图片自动加载
五 感谢
Databinding中ImageView的用法和坑(Java和Kotlin),附带Glide用法(https://blog.csdn.net/qq_33337504/article/details/98615593)
Android DataBinding (四) 自定义属性(https://blog.csdn.net/tianjf0514/article/details/75195124)