17
7

More than 3 years have passed since last update.

[Android] 連続クリック対策 (DataBindingにも対応)

Last updated at Posted at 2019-12-26

準備

こういう拡張関数を作っておく。(DataBinding 使わないなら @BindingAdapter("onSafeClick") の行は不要)

@BindingAdapter("android:onSafeClick")
fun View.setOnSafeClickListener(listener: View.OnClickListener) {
    this.setOnClickListener {
        it.isClickable = false
        it.postDelayed(300) { // 300ms内の連続クリックを無効に
            it.isClickable = true
        }
        listener.onClick(it)
    }
}

isClickable による制御が気になる場合は、this.setOnClickListener { の外側で前回クリックのタイムスタンプを保持しておいて比較、という対応でもいいかもしれない。

利用例

DataBinding を使う場合は次のようにリスナーをセットする。

<!-- View ならばなんでもいい -->
<TextView
    android:id="@+id/some_text_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="テスト"
    android:onSafeClick="@{() -> someViewModel.onSomeTextClicked()}"
/>

DataBinding 使わないなら、コードで次のようにリスナーをセットする。

someTextView.setOnSafeClickListener(View.OnClickListener {
    someViewModel.onSomeTextClicked()
})

コードでリスナーをセットする場合、次のような拡張関数を用意しておくとよりすっきり書ける。

fun View.setOnSafeClickListener(block: (View) -> Unit) {
    this.setOnSafeClickListener(View.OnClickListener {
        block.invoke(it)
    })
}

// ...

someTextView.setOnSafeClickListener {
    someViewModel.onSomeTextClicked()
}

補足

DataBinding を使う場合で、任意の引数を渡す場合は次のように書く。(この例だと整数1を渡している。)

android:onSafeClick="@{() -> someViewModel.onSomeTextClicked(1)}"

View のインスタンスを渡す場合は次のように。

android:onSafeClick="@{(view) -> someViewModel.onSomeTextClicked(view)}"

この場合(View のインスタンスを渡す場合)は、メソッドリファレンスに置き換えられる。

android:onSafeClick="@{someViewModel::onSomeTextClicked}"

改善案

300ms という数字を引数で渡せるようにするともっと便利かもしれない。(DataBinding でリスナーと数字、というふうに複数の引数を渡す必要があるので、その方法を調べる。)

17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7