Android ViewBinding with CustomView

Viewed 14723

I'd like to use try out the ViewBinding with custom view, for example:

MainActivity <=> layout_main.xml
MyCustomView <=> layout_my_custom_view.xml

layout_main.xml

<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.example.myapplication.MyCustomView
            android:id="@+id/custom_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</FrameLayout>

layout_my_custom_view.xml

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/line1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Line1" />

        <View
            android:id="@+id/divider"
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="#2389bb" />

        <TextView
            android:id="@+id/line2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Line2" />
</LinearLayout>

MainActivity

class MainActivity : AppCompatActivity() {

    private lateinit var binding: LayoutMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = LayoutMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.customView.line1.text = "Hello"
        binding.customView.line2.text = "World"
    }
}

In my MainActivity, I can use the binding to find MyCustomView but I can't further find @id/line1 and @id/line2 in MyCustomView. In this case, is it possible to use ViewBinding only or do I have to use findViewById or Kotlin synthetic ??

Thanks in advance.

3 Answers

ViewDataBinding.inflate doesn't generate of child view accessor inside custom view.

thus, you can't touch line1(TextView) via only use ViewDataBinding.

If you don't want using findViewById or kotlin synthetic, MyCustomView also needs to apply ViewDataBinding. try as below.

CustomView

class MyCustomView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
    private val binding =
        CustomLayoutBinding.inflate(LayoutInflater.from(context), this, true)

    val line1
        get() = binding.line1

    val line2
        get() = binding.line2
}

MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding = ActivityMainBinding.inflate(LayoutInflater.from(this))
    setContentView(binding.root)

    with(binding.customView) {
        line1.text = "Hello"
        line2.text = "World"
    }
}

Another approach is to return the CustomView binding object.

class CustomView constructor(context: Context, attrs: AttributeSet?) : 
    ConstraintLayout(context, attrs){
                
        private val _binding: CustomViewBinding = CustomViewBinding.inflate(
                        LayoutInflater.from(context), this, true)
                
                val binding get() = _binding    
        }

And then in your Activity or Fragment:

binding.customView.binding.line1?.text = "Hello"
binding.customView.binding.line2?.text = "World"

I believe you can have setter in your custom view. Since ViewBinding generates binding class for your main layout, it should return you the CustomView class. Thus, you can use the setter you just wrote for changing the texts.

Related