android 数据绑定(6)自定义绑定方法、双向数据绑定
1.官方文档
https://developer.android.com/topic/libraries/data-binding/binding-adapters
https://developer.android.com/topic/libraries/data-binding/two-wa
2.自定义绑定
2.1 系统定义的绑定方法
假设在绑定布局文件中使用app:aaaaa 的属性,绑定库自动尝试查找方法 setAaaaa(arg)。
- 按app:aaaaa 时传递的参数, 找到参数匹配或兼容的那个方法setAaaaa
- 不会考虑属性的命名空间
- 搜索方法时仅使用属性名称和类型
- 假设类Student包含 setTtttt 这个方法,那么可以直接在布局文件中使用 app:ttttt 这个属性。
2.2 自定义绑定的方法
- a.重新绑定属性与对应的方法
@BindingMethods(value = [
BindingMethod(
type = ImageView::class,
attribute = "android:tint",
method = "setImageTintList")])
上述代码把 android:tint 这个属性绑定到了setImageTintList方法。官方文档中并没有给出这段应该放哪里,放在类里面编译不过,通过官方完整示例中发现它是全局的。

- b.修改系统已经定义好的方法
@androidx.databinding.BindingAdapter("android:paddingLeft")
@JvmStatic
fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
if (oldPadding != newPadding) {
view.setPadding(,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
}重新定义了 android:paddingLeft属性,注意,调用的时候 android:paddingLeft='@{16}' 才匹配这个方法,android:paddingLeft="16dp" 还是系统的那个方法。
出现冲突时,自定义的绑定方法会替换数据绑定库提供的默认方法.
重新定义系统已经存在的属性没意义,这个方法要以 '@{16}‘ 这种 方式调用,android:paddingLeft="16dp" 无效
- c.把多个属性联合在一起,绑定个方法
@JvmStatic
@androidx.databinding.BindingAdapter(value = ["imageUrl", "error"], requireAll = false)
fun loadImage(view: ImageView, url: String, error: Drawable) {
Picasso.get().load(url).error(error).into(view)
}requireAll = false 的含义是 单独使用imageUrl,error其中一个属性的时候,就绑定这个方法,true就是必需同时使用这两个属性的时候才绑定这个方法。
使用
<ImageView
android:id="@+id/imageView2"
android:layout_width="64dp"
android:layout_height="64dp"
app:error='@{@drawable/error}'
app:imageUrl='@{"sdfsd.com/fef.ppppjnpng"}'
/>
2.3 类型转换 @BindingConversion
作用:使用这个 注解可以定义一个类型A到类型B在转换函数,函数名的格式为
convertAToB,如 convertStringToData
@JvmStatic
@androidx.databinding.BindingConversion
fun convertStringToData(name : String) = Data()
3. 双向绑定
3.1 单向的问题
默认是单向绑定,控件与用户的交互(如输入新的名字,点单选框和复选框)不会自动修改对应的绑定数据对象,要在代码里手动处理相应的控件事件,在事件函数里修改数据对象。如:
val data = Data()
lateinit var binding : Way2Binding
val nameWatcher = object : TextWatcher{
override fun afterTextChanged(p0: Editable?) {
val txt = p0.toString()
data.name = txt
binding.invalidateAll()
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
} fun initBinding(){
binding.data = data
binding.normalEdt.addTextChangedListener(nameWatcher)
}
3.2 使用双向绑定
使用双向绑定可以简化这个问题,减少相应代码。
用 @={} 表示可接收属性的数据更改并同时监听用户更新.
<EditText
...
android:text='@={data.name,default=@string/data_name}'
.../>
这样当用户在这个EditText上输入新的内容后,直接更新到绑定的数据对象。
注意: @={} 不可以使用格式化的@string/xx
3.3 自定义的属性使用双向绑定
a.自定义属性的 setXXX
@BindingAdapter("dataName")
@JvmStatic fun setDataName(edt : EditText, txt : String){
edt.setText(txt)
}
b.自定义属性的 getXXX
@InverseBindingAdapter(attribute = "dataName")
@JvmStatic fun getDataName(edt : EditText) : String{
return edt.text.toString()
}
注意:attribute = 不可少,否则编译不过。
c.编写属性变化监听器及想要监听的事件
@BindingAdapter("dataNameAttrChanged")
@JvmStatic fun setListener(edit : EditText, listener: InverseBindingListener?) {
Log.e("dataNameAttrChanged","txt = ${edit.text.toString()}")
var txt = ""
edit.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(p0: Editable?) {
Log.e("dataNameAttrChanged","afterTextChanged")
if (txt != p0.toString()){
listener?.onChange()
txt = p0.toString()
}
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
})
}
- InverseBindingListener 是属性变化监听器
- 这个 EditText 监听的事件是 textChanged
注意: listener?.onChange() 容易死 循环,要判断下原内容与新内容,不一样才调用这个函数。上述代码中的高亮部分。
d.布局文件中使用
<EditText app:dataName='@={data.name}' ... >
3.4 类型转换的双向绑定
使用类型转换时,也可以使用双向绑定,但是要指定一个反向转换的函数。用 @InverseMethod("转换函数名") 来声明。
@file:JvmName("Converter")
package com.example.databind
import androidx.databinding.InverseMethod
class A (var name: String)
@InverseMethod("a2String")
fun string2a(string: String) : A{
return A(string)
}
fun a2String(a : A) : String{
return a.name
}
在布局文件中
<EditText android:text='@={Converter.a2String(a)}' />
3.5 支持双向绑定的内置属性
| 控件 | 属性 | 绑定适配器所在的类 |
|---|---|---|
AdapterView |
android:selectedItemPositionandroid:selection |
AdapterViewBindingAdapter |
CalendarView |
android:date |
CalendarViewBindingAdapter |
CompoundButton |
android:checked |
CompoundButtonBindingAdapter |
DatePicker |
android:yearandroid:monthandroid:day |
DatePickerBindingAdapter |
NumberPicker |
android:value |
NumberPickerBindingAdapter |
RadioButton |
android:checkedButton |
RadioGroupBindingAdapter |
RatingBar |
android:rating |
RatingBarBindingAdapter |
SeekBar |
android:progress |
SeekBarBindingAdapter |
TabHost |
android:currentTab |
TabHostBindingAdapter |
TextView |
android:text |
TextViewBindingAdapter |
TimePicker |
android:hourandroid:minute |
TimePickerBindingAdapte |
android 数据绑定(6)自定义绑定方法、双向数据绑定的更多相关文章
- 【Angular 5】数据绑定、事件绑定和双向绑定
本文为Angular5的学习笔记,IDE使用Visual Studio Code,内容是关于数据绑定,包括Property Binding.Class Binding.Style Binding. 在 ...
- 2-4 Vue中的属性绑定和双向数据绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue学习之vue属性绑定和双向数据绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- angular 双向数据绑定与vue数据的双向数据绑定
二者都是 MVVM 模式开发的典型代表 angular 是通过脏检测实现,angular 会将 UI 事件,请求事件,settimeout 这类延迟的对象放入到事件监测的脏队列,当数据变化的时候,触发 ...
- Angularjs进阶笔记(2)-自定义指令中的数据绑定
有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题. 一. 自定义指令 自定义指令,是Angularjs用来实 ...
- angularJs初体验,实现双向数据绑定!使用体会:比较爽
使用初体验:ng 双向数据绑定: 最简单的双向数据绑定:(使用默认模块控制) <body ng-app> <input type="text" ng-model= ...
- 组件使用v-model、$listeners、.sync(区别于v-model的双向数据绑定)
自定义组件 自定义组件的v-model 首先我们先说一下在自定义组件中使用v-model的必要条件 在自定义的组件中要有input(这里我们先不讨论单选复选框) 在自定义组件的模板对象中要有props ...
- vue 双向数据绑定的实现学习(一)
前言:本系列学习笔记从以下几个点展开 什么是双向数据绑定 双向数据绑定的好处 怎么实现双向数据绑定 实现双向数据数据绑定需要哪些知识点 数据劫持 发布订阅模式 先看看我们要实现的目标是什么,如下动图: ...
- ng 双向数据绑定
1.方向1:model->View模型数据绑定到视图 绑定的方式:①双花括号 ②常见的ng指令(ngRepeat ngIf ngShow....) 效果:数据一旦绑定到视图上,随着数据的修改,视 ...
随机推荐
- C++的常用输入及其优化以及注意事项
$\mathcal{P.S:}$ 对于输入方式及其优化有了解的大佬可直接阅读$\mathcal{Part}$ $\mathcal{2}$ 特别鸣谢:@归斋目录: $\mathcal{Part}$ $\ ...
- 详解Flask上下文
上下文是在Flask开发中的一个核心概念,本文将通过阅读源码分享下其原理和实现. Flask系列文章: Flask开发初探 WSGI到底是什么 Flask源码分析一:服务启动 Flask路由内部实现原 ...
- win10 安装tensorflow2.0 GPU版本遇到的坑
背景:我的机器上tensorflow 1.14 & 2.0,这俩版本都有,之前都是用1.14版本,今天试一下2.0尝尝鲜, 结果就掉坑去了 把CUDA10.1 和 cudnn 安装 ...
- boost之signal的使用
文章目录 简介 代码 模板实现: 测试代码 运行结果 简介 boost是C++的一个扩展库,被称为C++准标准库,里面的组件很丰富,并且引用方便,85%的组件只需要引用头文件即可使用. 并且在嵌入式系 ...
- 理解HTTP的POST和PUT的区别
1.HTTP Methods HTTP Methods GET POST PUT HEAD DELETE PATCH OPTIONS GET is used to request data from ...
- JS笔记 运算符 函数
1.运算符 1.位运算符 将数字转换为二进制后进行运算 只做整数运算,如果是小数的话,则去掉小数位再运算 2.位运算 1.按位 与:& 语法:a&b; 2.按位 或| 语法:a|b 任 ...
- 15、Java中级进阶 面向对象 继承
1.何为面向对象 其本质是以建立模型体现出来的抽象思维过程和面向对象的方法(百度百科)是一种编程思维,也是一种思考问题的方式 如何建立面向对象的思维呢?1.先整体,再局部2.先抽象,再具体3.能做什么 ...
- JavaIO流,万物皆文件
引入IO的原因 基本概念: 数据源和流的概念 IO流的概念细分 IO流的体系 IO流在Java中的流对象:inputStream .... Java对象的序列化和反序列化: 1 为什么需要序列化和反序 ...
- 准确率、精确率、召回率、F1
在搭建一个AI模型或者是机器学习模型的时候怎么去评估模型,比如我们前期讲的利用朴素贝叶斯算法做的垃圾邮件分类算法,我们如何取评估它.我们需要一套完整的评估方法对我们的模型进行正确的评估,如果模型效果比 ...
- Netty(二):如何处理io请求?
文接上一篇.上篇讲到netty暴露一个端口出来,acceptor, handler, pipeline, eventloop 都已准备好.但是并没体现其如何处理接入新的网络请求,今天我们就一起来看看吧 ...