如何在自定义视图/组件中双向绑定 Seekbar?
How to 2-way bind a Seekbar in custom view / component?
我正在尝试在包含 SeekBar 的自定义视图上使用双向数据绑定。布局相当简单,但我需要在整个项目中重复使用它,因此将其包装到自定义 view/component
<androidx.constraintlayout.widget.ConstraintLayout ... />
<TextView .../>
<TextView .../>
<SeekBar
android:id="@+id/ds_seekbar"
android:layout....
android:max="9"
android:min="0"
android:progress="0"
</androidx.constraintlayout.widget.ConstraintLayout>
支持代码看起来像这样(减少)
CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
init {
LayoutInflater.from(context).inflate(R.layout.custom_view, this, true)
ds_description.setOnClickListener(this)
}
override fun onClick(view: View) {
//onClick implementation
}
}
我可以在 ViewModel 中为将要使用此自定义视图的布局进行绑定,其中的 BindingAdapter 具有自定义属性(例如 app:seekbar),但将使用自定义视图多次,我更愿意将大量所需的逻辑放入视图中,并在 ViewModel 中进行 "lighter" 处理。
我阅读了 和其他一些文章,它们看起来有点不同,但主题相同,但是无论我如何编写 getter 和 setter,我总是 运行 进入 kapt 异常,它找不到 getter/setter。
要么我没有正确注释这些方法,要么它们的签名有误。
理想情况下我想要这样的东西:
CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener, SeekBar.OnProgressChangedListener {
... ds_seekbar.setOnProgressChangedListener(this)
然后在主布局中有 app:progress(如果有人可以展示它是如何完成的,甚至更好 android:progress)在传递我的对象时用于绑定的自定义视图。
好吧,经过越来越多的头痛之后,这就是我带来的东西,它似乎有效。这是正确的方法还是 performant/reliable 是怎样的——我不确定
@InverseBindingMethods(InverseBindingMethod(type = CustomView::class, attribute = "progress", event = "progressAttrChanged"))
CustomView @JvmOverloads constructor(...
private var progress = 0
private var mInverseBindingListener: InverseBindingListener? = null
cv_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
progress = i + 1
if (mInverseBindingListener != null) {
mInverseBindingListener!!.onChange()
cv_indicator.text = progress.toString()
}
}...
})
fun getProgress(): Int {
return progress
}
fun setProgress(p: Int) {
if (progress != p) {
progress = p
}
}
fun setProgressAttrChanged(inverseBindingListener: InverseBindingListener?) {
if (inverseBindingListener != null) {
mInverseBindingListener = inverseBindingListener
}
}
那么XML就是
<com.xxx.CustomView
android:id="@+id/xxx"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:progress="@={viewModel.dataobject.value}"
....
/>
我正在尝试在包含 SeekBar 的自定义视图上使用双向数据绑定。布局相当简单,但我需要在整个项目中重复使用它,因此将其包装到自定义 view/component
<androidx.constraintlayout.widget.ConstraintLayout ... />
<TextView .../>
<TextView .../>
<SeekBar
android:id="@+id/ds_seekbar"
android:layout....
android:max="9"
android:min="0"
android:progress="0"
</androidx.constraintlayout.widget.ConstraintLayout>
支持代码看起来像这样(减少)
CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
init {
LayoutInflater.from(context).inflate(R.layout.custom_view, this, true)
ds_description.setOnClickListener(this)
}
override fun onClick(view: View) {
//onClick implementation
}
}
我可以在 ViewModel 中为将要使用此自定义视图的布局进行绑定,其中的 BindingAdapter 具有自定义属性(例如 app:seekbar),但将使用自定义视图多次,我更愿意将大量所需的逻辑放入视图中,并在 ViewModel 中进行 "lighter" 处理。
我阅读了
要么我没有正确注释这些方法,要么它们的签名有误。
理想情况下我想要这样的东西:
CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener, SeekBar.OnProgressChangedListener {
... ds_seekbar.setOnProgressChangedListener(this)
然后在主布局中有 app:progress(如果有人可以展示它是如何完成的,甚至更好 android:progress)在传递我的对象时用于绑定的自定义视图。
好吧,经过越来越多的头痛之后,这就是我带来的东西,它似乎有效。这是正确的方法还是 performant/reliable 是怎样的——我不确定
@InverseBindingMethods(InverseBindingMethod(type = CustomView::class, attribute = "progress", event = "progressAttrChanged"))
CustomView @JvmOverloads constructor(...
private var progress = 0
private var mInverseBindingListener: InverseBindingListener? = null
cv_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
progress = i + 1
if (mInverseBindingListener != null) {
mInverseBindingListener!!.onChange()
cv_indicator.text = progress.toString()
}
}...
})
fun getProgress(): Int {
return progress
}
fun setProgress(p: Int) {
if (progress != p) {
progress = p
}
}
fun setProgressAttrChanged(inverseBindingListener: InverseBindingListener?) {
if (inverseBindingListener != null) {
mInverseBindingListener = inverseBindingListener
}
}
那么XML就是
<com.xxx.CustomView
android:id="@+id/xxx"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:progress="@={viewModel.dataobject.value}"
....
/>