如何在自定义视图上使用视图绑定

How to use View Binding on custom views

视图绑定已作为 Android Jetpack

的一部分发布

文档:https://developer.android.com/topic/libraries/view-binding

我的问题是,如何将视图绑定与自定义视图结合使用。 Google 文档只有展示 Activity 和片段。

我试过了,但是没有显示。

LayoutInflater inflater = LayoutInflater.from(getContext());

然后,我用了这个,但还是不行。

LayoutInflater inflater = (LayoutInflater)
            getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

我想我可能没有针对我的视图定位正确的布局 inflater 但不确定。

要使用视图绑定,您需要使用生成的绑定 class 而不是 LayoutInflater,例如,如果布局名称是 result_profile.xml 那么您需要使用 ResultProfileBinding 为:

class CustomView @kotlin.jvm.JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private lateinit var binding: ResultProfileBinding

    init { // inflate binding and add as view
        binding = ResultProfileBinding.inflate(LayoutInflater.from(context))
        addView(binding.root)
    }

}
  1. 自动生成 class : result_profile.xml -> ResultProfileBinding(布局名称,附加 Binding
  2. 膨胀绑定

    ResultProfileBinding.inflate(LayoutInflater.from(context))
    
  3. 使用 addView 将视图添加到层​​次结构中:

    addView(binding.root)
    

注意:如果您从 ConstraintLayout(是父 class)扩展,则使用

如果您尝试将视图绑定与根视图一起使用,这对我有用:

class CustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {

    private lateinit var binding: CustomViewBinding

    override fun onFinishInflate() {
        super.onFinishInflate()
        binding = CustomViewBinding.bind(this)
    }
}

只需通知根,是否要附加到它

init { // inflate binding and add as view
    binding = ResultProfileBinding.inflate(LayoutInflater.from(context), this)
}

init { // inflate binding and add as view
    binding = ResultProfileBinding.inflate(LayoutInflater.from(context), this, true)
}

使用哪种 inflate 方法将取决于 xml 中的根布局类型。

这是我能想到的最简单的 kotlin 答案。它是一个自定义视图,仅包装了一个 TextView 并提供了一个 update(s:String) 函数来更新文本。

<!-- view_stub.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView android:id="@+id/myTextView" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
</layout>

// StubView.kt
class StubView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : FrameLayout(context,attrs,defStyleAttr) {

    val binding = ViewStubBinding.inflate(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
            .also { addView(it.root) }

    fun update(updatedText: String) {
        binding.myTextView.text = updatedText
    }
}

我喜欢这个答案的两点是:

  1. bindingval 而不是 var。我尽量限制 var 的数量。
  2. addViewval binding 密切相关,使用 also {} 范围函数而不是 init {} 子句,使 View 实例化感觉更加明确。

有人可能会争辩说 addView() 确实是一种副作用,应该在 init {} 部分中,以便它与 binding val 的声明分开。我会反驳 - 声明一个 val 然后将它提供给需要它的一段代码,这对我来说并不是副作用。

您可以立即初始化视图绑定属性

private val binding = CustomViewBinding.inflate(LayoutInflater.from(context), this)