1

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

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

This is good, but problem is i should repeat ' view?.preventDoubleClick() ' in every onClick() method (If I understood correctly) , do you have solution for this ?
No I never done it before, because it's not a good idea to do a method on all views. Even if you done that you must add a flag that means you must add it to views
2

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
    }

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.