ボタン連打を防ぐ方法 - kotlin

この記事は、[Android #2 Advent Calender 2020](https://qiita.com/advent-calendar/2020/android-2) 12日目の記事です。

# できるもの

![android-sample-sigle-tap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249786/09609e14-f73a-e894-c777-892087aba777.gif)

# やること
1. タップ前の画面のレイアウトを追加
2. タップ後の画面のレイアウトを追加
3. extディレクトリに、ViewExt.ktを生成
4. Activityから呼び出し

## 1. タップ前の画面のレイアウトを追加

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="204dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

```

2. タップ後の画面のレイアウトを追加

```activity_next_page.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NextPageActivity">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="NextPage"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

## 2. extディレクトリに、ViewExt.ktを生成
ViewExt.ktを生成し、

![スクリーンショット 2020-12-12 11.21.57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249786/921c5755-f982-585e-fa1d-8d95b9d59a86.jpeg)

ボタン連打を防ぐための関数を、ViewExt.ktに`拡張関数`として定義

```ViewExt.kt
private const val DELAY_TIME = 2000

fun View.setOnSingleClickListener(listener: () -> Unit) {
    var pushedAt = 0L
    val currentTime = System.currentTimeMillis()

    Log.d("TAP", "tap")

    if (currentTime - pushedAt < DELAY_TIME) return
    pushedAt = System.currentTimeMillis()
    listener()
}
```

## 4. Activityから呼び出し

```MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textview = findViewById<View>(R.id.textView) as TextView
        val button = findViewById<Button>(R.id.button) as Button

        textview.setOnSingleClickListener {
            startActivity(Intent(this, NextPageActivity::class.java))
        }
        button.setOnSingleClickListener {
            startActivity(Intent(this, NextPageActivity::class.java))
        }
    }
}
```

終了です

# 参考
[ボタン連打されてしまい不正な動作をするのはよくある話](https://kojion.com/posts/1057)
[kotlinで定数を定義する時【const】vs【val】](https://qiita.com/takusemba/items/f278e9e9e9217f0d6632)