androidkotlinandroid-databindingmethod-referenceonlongclicklistener

How to write a generic BindingAdapter to setup an OnLongClickListener?


In my Android project I use the following BindingAdapter to wire an OnLongClickListener to views and their corresponding view model.

@JvmStatic
@BindingAdapter(value = ["onLongClick", "onLongClickText"], requireAll = true)
fun setOnLongClickListener(view: View, viewModel: MyViewModel, text: CharSequence) {
    view.setOnLongClickListener {
        viewModel.onButton1LongClick(text)
        true
    }
}

... in the XML layout:

app:onLongClick="@{viewModel}"
app:onLongClickText="@{otherView.text}"

And here is a second adapter in the same view model class:

@JvmStatic
@BindingAdapter("onLongClick")
fun setOnLongClickListener(view: View, viewModel: MyViewModel) {
    view.setOnLongClickListener {
        viewModel.onButton2LongClick()
        true
    }
}

... in the XML layout:

app:onLongClick="@{viewModel}"

I would love to make the BindingAdapter reuseable so it can be wired to different views. I thought I could pass the actual method reference from the XML. Here is my not working draft:

@JvmStatic
@BindingAdapter(value = ["onLongClick", "onLongClickText"], requireAll = true)
fun setOnLongClickListener(view: View, onLongClick: (CharSequence) -> Unit, text: CharSequence) {
    view.setOnLongClickListener {
        onLongClick.invoke(text)
        true
    }
}

... in the XML layout:

app:onLongClick="@{(view) -> viewModel.onButton1LongClick(???)}"
app:onLongClickText="@{otherView.text}"

Solution

  • ViewModel:

    class MyViewModel : ViewModel() {
    
        private val TAG = "MyViewModel"
    
        fun onButton1LongClick(text: CharSequence) : Unit {
            Log.d(TAG, "onButton1LongClick: " + text)
        }
        val f1 : (CharSequence) -> Unit = {text -> onButton1LongClick(text)}
    
        fun onButton2LongClick() {
            Log.d(TAG, "onButton2LongClick")
        }
        val f2 : () -> Unit = {onButton2LongClick()}
    }
    

    Binding Adapters:

    @JvmStatic
    @BindingAdapter(value = ["onLongClick", "onLongClickText"], requireAll = true)
    fun setOnLongClickListener(view: View, onLongClick: (CharSequence) -> Unit, text: String?) {
        view.setOnLongClickListener {
            onLongClick.invoke(text?:"")
            true
        }
    }
    
    @JvmStatic
    @BindingAdapter("onLongClick")
    fun setOnLongClickListener(view: View, onLongClick: () -> Unit) {
        view.setOnLongClickListener {
            onLongClick.invoke()
            true
        }
    }
    

    XML layout:

    <EditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <Button
        onLongClick="@{viewModel.f1}"
        onLongClickText='@{editText.text.toString()}'
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1" />
    
    <Button
        onLongClick="@{viewModel.f2}"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 2" />