Danial Nazari
Danial Nazari

Reputation: 121

Custom click event with android data binding

i want to set a certain action (like preventing multiple click) on every click event in data binding , in other phrase when a user click on each view, first do a specific action and after that do action relevant to clicked view(different for each view). How can I do this? description: i implement MVVM and use databinding

Upvotes: 1

Views: 3588

Answers (3)

itsgenius_thulc
itsgenius_thulc

Reputation: 137

So, today(2022) I had the same use case in one of my projects and i was able to figure out a way to implement custom click listeners for android views using data binding and custom adapters.

The use case is :

Click event should not be triggered twice or to prevent accidental clicks from the user

I created a file called ViewExtensions.kt and added the following code

 class DebouncingOnClickListener(
      private val intervalMillis: Long,
      private val doClick: (() -> Unit)
    ) : View.OnClickListener {

    override fun onClick(v: View) {
        if (enabled) {
            enabled = false
            v.postDelayed(ENABLE_AGAIN, intervalMillis)
            doClick()
        }
    }

    companion object {
        @JvmStatic
        var enabled = true
        private val ENABLE_AGAIN =
            Runnable { enabled = true }
    }
}

@BindingAdapter("singleClick")
fun View.setSingleClick(doClick: () -> Unit) =
    setOnClickListener(
        DebouncingOnClickListener( 
            intervalMillis = 5000, //5ms delay for click event
            doClick = doClick
        )
    )

The debouncing click is used to defer the click for the given time, and in the xml called the click event like below

 <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me"
        app:singleClick="@{()->fragment.clicked()}" />

Now I'm able to listen for click events on both fragment and in the viewmodel and the click is deferred for the given amount of time.

Hence the user cannot click the view accidentally multiple times.

References: https://proandroiddev.com/ensure-single-click-on-android-butterknife-did-it-right-48ef56153c78

Upvotes: 0

Manoj Mohanty
Manoj Mohanty

Reputation: 370

First: create a mutableLiveData of type boolean in your SomeViewModel class with initial value to true

val data = MutableLiveData<Boolean>(true)

next in your xml


            <data>
                <variable
                    name="viewModel"
                    type="..SomeViewModel" />
            </data>

    <View
    android:enabled = "@{viewModel.data}" // if working with button
    android:clickable = "@{viewModel.data}" // for views which dont have enable tag
    android:onClick="@{() -> viewModel.disableButtonAndPerformRequiredAction()}"/>

// In viewmodel
    fun disableButtonAndPerformRequiredAction() {
    data.value = false // it will disable the click for the view
    // Perform other tasks 
    // post executing required task set 
    data.value = true // it will again enable the click for the view
    }

Upvotes: 2

mahdi shahbazi
mahdi shahbazi

Reputation: 2132

This is what I do in this situation.

First: add onclick in your xml that call method on view model and pass it view

XML:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="model"
            type="....ViewModel" />

    </data>

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:onClick="@{(v)-> model.onClick(v)}"/>
</layout>

Second: adding prevent double click with kotlin extensions Kotlin:

fun View.preventDoubleClick() {
    isClickable = false
    Handler().postDelayed({ isClickable = true },500L)
}

Third:

Kotlin:

fun onClick(view: View?){
     view?.preventDoubleClick()
}

now you have access to your view that clicked in view model. remember make your view nullable. this help you when for example you want add unit test for your method you can just send view null.

Upvotes: 2

Related Questions