Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android ViewBinding with CustomView

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.

like image 522
Z.J Hung Avatar asked Feb 27 '20 02:02

Z.J Hung


2 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"
    }
}
like image 124
Ethan Choi Avatar answered Oct 29 '22 21:10

Ethan Choi


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"
like image 42
Igor Fridman Avatar answered Oct 29 '22 20:10

Igor Fridman