How to use View Binding on custom views

Viewed 47328

View Binding got released as part of Android Jetpack

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

My question is, how to use view binding with custom views. Google documentation has only show-cased Activity and fragment.

I tried this, but nothing was shown.

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

And then, I used this one, but again, no luck.

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

I guess maybe I don't target the correct layout inflater for my view but not sure.

5 Answers

Just inform the root, and whether you want to attach to it

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

or

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

which inflate method to use will depend on the root layout type in xml.

To use the view binding, you need to use the generated binding class not the LayoutInflater, for example, if the layout name is result_profile.xml then you need to use ResultProfileBinding as:

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. Auto generated class : result_profile.xml -> ResultProfileBinding(name of layout, appended with Binding )
  2. Inflate the binding

    ResultProfileBinding.inflate(LayoutInflater.from(context))
    
  3. Use addView to add the view in the hierarchy as:

    addView(binding.root)
    

Note: If you are extending from ConstraintLayout(is the parent class) then use constraint set

You can initialize the view binding property right away

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

If you are trying to use View Binding with the root view, this is working for me:

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)
    }
}

This is the simplest kotlin answer I can think of. It's a custom view that just wraps a single TextView and provides an update(s:String) function to update the text.

<!-- 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
    }
}

The two things I like about this answer are:

  1. binding is a val instead of a var. I try to limit the number of vars as much as possible.
  2. The addView is closely associated with the val binding using the also {} scope function instead of an init {} clause, making the instantiation of the View feel much more declarative.

One could argue that the addView() is really a side effect and should be in the init {} section so that it is separate from the declaration of the binding val. I would argue the opposite -- declaring a val then feeding it to a section of code that needs it does not feel like a side effect to me.

Related