在使用Databinding的过程中 因为用了自定义View
自定义View在使用单向双向绑定与双向绑定的时候
我们需要去做绑定适配
目前网上关于自定义View双向绑定的文章并不是很多
而且有一些方法随着Databinding的更新已经无效了
现在把自己的方法写出来 授人与渔
package com.pcf.databindingrecyclerview
import android.content.Context
import android.text.Editable
import android.text.InputType
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.ViewGroup
import android.widget.*
import androidx.databinding.InverseBindingListener
import com.pcf.customize.binding.DensityUtil
import com.pcf.customize.binding.NumberInputFilter
import com.pcf.customize.binding.R
class GoodsCounterView : LinearLayout {
var listener :InverseBindingListener ?= null
lateinit var editText: EditText
lateinit var reduceButton: ImageButton
lateinit var addButton: ImageButton
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
// val typedArray = context.obtainStyledAttributes(attrs, R.styleable.goods_Counter)
// val count = typedArray.getInt(R.styleable.goods_Counter_count, 1)
setVerticalGravity(HORIZONTAL)
gravity = Gravity.CENTER_VERTICAL
val buttonWidth = DensityUtil.dp2px(37.33f)
reduceButton = ImageButton(context)
reduceButton.layoutParams = ViewGroup.LayoutParams(buttonWidth.toInt(), buttonWidth.toInt())
reduceButton.setImageResource(R.drawable.selector_good_reduce)
reduceButton.background = resources.getDrawable(R.color.gray_fbfbfb)
reduceButton.isEnabled = false
val textViewWidth = DensityUtil.dp2px(47.33f)
editText = EditText(context)
editText.width = textViewWidth.toInt()
editText.height = buttonWidth.toInt()
editText.gravity = Gravity.CENTER
editText.setTextColor(resources.getColor(R.color.blue_32374a))
editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 19f)
editText.inputType = InputType.TYPE_CLASS_NUMBER
editText.background = resources.getDrawable(android.R.color.transparent)
// editText.setText(count.toString())
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
parseNum()
//触发反向数据的传递
// if (mInverseBindingListener != null) {
// mInverseBindingListener?.onChange()
// }
}
})
addButton = ImageButton(context)
addButton.layoutParams = LayoutParams(buttonWidth.toInt(), buttonWidth.toInt())
addButton.setImageResource(R.drawable.selector_good_add)
addButton.background = resources.getDrawable(R.color.gray_fbfbfb)
addView(reduceButton)
addView(editText)
addView(addButton)
reduceButton.setOnClickListener {
var num = editText.text.toString().toLong()
num -= 1
editText.setText(if (num > 1) num.toString() else "1")
if (num <= 1) {
reduceButton.isEnabled = false
}
}
addButton.setOnClickListener {
var num = editText.text.toString().toLong()
num += 1
editText.setText(num.toString())
reduceButton.isEnabled = true
}
editText.filters = arrayOf(NumberInputFilter())
}
private fun parseNum() {
val text = editText.text.toString()
if (text.isNotEmpty()) {
var num = text.toLong()
addButton.isEnabled = true
reduceButton.isEnabled = num > 1
} else {
reduceButton.isEnabled = false
addButton.isEnabled = false
}
listener?.onChange()
}
fun setText(text: String) {
editText.setText(text)
}
fun getText(): String {
return editText.text.toString()
}
}
apply plugin: 'kotlin-kapt'
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 29
buildToolsVersion "29.0.1"
defaultConfig {
applicationId "com.pcf.customize.binding"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
package com.pcf.customize.binding
import androidx.databinding.Bindable
class GoodsBean : ObservableViewModel {
constructor(count: Long) : super() {
this.count = count
}
var count: Long = 0
@Bindable
set(value) {
if (value == field) {
return
}
field = value
notifyPropertyChanged(BR._all)
}
}
//单向绑定的语法
@{}
//双向绑定的语法
@={}
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="goods"
type="com.pcf.customize.binding.GoodsBean" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.pcf.customize.binding.GoodsCounterView
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:numberOfSets="@={goods.count}"
android:gravity="center"/>
<TextView
android:layout_marginTop="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(goods.count)}"
android:gravity="center"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
package com.pcf.customize.binding
import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
/**
* binding 适配器
* */
object BindingAdapters {
@BindingAdapter(value = ["numberOfSets"], requireAll = false)
@JvmStatic
fun setNumberOfSets(view: GoodsCounterView, value: Long) {
view.setText(value.toString())
}
@InverseBindingAdapter(attribute = "numberOfSets", event = "numberOfSetsAttrChanged")
@JvmStatic
fun getNumberOfSets(view: GoodsCounterView): Long {
val text = view.getText()
return if (text.isEmpty()) 0 else text.toLong()
}
@BindingAdapter(value = ["numberOfSetsAttrChanged"], requireAll = false)
@JvmStatic
fun setListener(view: GoodsCounterView, listener: InverseBindingListener?) {
view.listener = listener
}
}
var listener :InverseBindingListener ?= null
private fun parseNum() {
val text = editText.text.toString()
if (text.isNotEmpty()) {
var num = text.toLong()
addButton.isEnabled = true
reduceButton.isEnabled = num > 1
} else {
reduceButton.isEnabled = false
addButton.isEnabled = false
}
listener?.onChange()
}