개발새발 - IT 기술블로그
article thumbnail

안녕하세요. 이번 포스팅에선 뷰의 클릭 이벤트가 여러번 중복 발생해서 생기는 에러들을 해결하기 위한 방법을 소개드리려고 합니다.

 

방식은 뷰의 클릭 리스너를 상속받는 클래스를 생성하고, 클릭 이벤트가 발생했을 때의 시간과 현재 시간을 비교하여 일정시간이 지나기 전까지 클릭을 막는 형태입니다.

 

 

전체 예제 코드를 보여드린 후 설명드리겠습니다 👀

 

 


시연

저는 버튼 하나와 텍스트뷰 하나를 생성해 버튼을 클릭하면 텍스트의 숫자가 하나씩 증가하는 예제를 만들었습니다.

아래 코드와 같이 중복 클릭 방지시간은 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">

    <TextView
        android:id="@+id/countTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="15dp"
        android:gravity="center"
        android:text="0"
        android:textColor="@color/black"
        android:textSize="20sp"
        app:layout_constraintBottom_toTopOf="@+id/clickBtn" />

    <Button
        android:id="@+id/clickBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Increase"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

<OnSingleClickListener.kt>

import android.os.SystemClock
import android.view.View
import android.widget.Toast

abstract class OnSingleClickListener() : View.OnClickListener {
    private var mLastClickTime: Long = 0
    abstract fun onSingleClick(v: View?)
    override fun onClick(v: View) {
        val currentClickTime = SystemClock.uptimeMillis()
        val elapsedTime = currentClickTime - mLastClickTime
        mLastClickTime = currentClickTime
        // 중복클릭 아닌 경우
        if (elapsedTime > MIN_CLICK_INTERVAL) {
            onSingleClick(v)
        } else {
            //TODO 중복클릭 발생시 처리
        }
    }

    companion object {
        // 중복 클릭 방지 시간 설정 ( 해당 시간 이후에 다시 클릭 가능 )
        private const val MIN_CLICK_INTERVAL: Long = 1000
    }
}

 

 

<MainActivitiy.kt>

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    var count = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btn: Button = findViewById(R.id.clickBtn)
        val tv: TextView = findViewById(R.id.countTextView)

        btn.setOnClickListener(object : OnSingleClickListener() {
            override fun onSingleClick(v: View?) {
                count++
                tv.text = count.toString()
            }
        })
    }
}

 

 

 


설명

보통 개발자들이 버튼을 만들고 클릭 이벤트를 부여할 때 그 버튼을 누르는 사용자의 모습을 아래와 같이 상상하곤 하죠.

 

 

 

 

 

 

 

 

 

하지만 간혹 상상을 벗어나는 경우들도 있습니다 😱

 

 

 

 

 

 

이로인해 클릭을 통해 서버와 통신하거나 페이지의 이동다이얼로그의 생성등을 처리하는 경우, 처리가 완료되기 전에 버튼을 다시 클릭하면 창이 중복되어 생성되기도 하고 필요하지 않은 통신이 발생하기도 합니다.

 

 

그럴 때 클릭 자체를 isEnable = false로 막아버리거나, Progress를 최상단에 띄워 로딩을 보여주는 등 여러가지 방법으로 처리 할 수 있겠지만 제가 이번에 소개드린 방법은 일정 시간동안 클릭을 막는 방법입니다.

 

 

기본적인 구조는 위에서 설명드렸듯이 OnSingleClick 메서드를 인스턴스를 가지지 않고 반드시 상속받아야하는 abstract 클래스로 생성하고, 뷰의 OnClick 메서드가 발생할 때 마다 mLastClickTimecurrentTime을 비교하여 지정한 시간인 MIN_CLICK_INTERVAL을 넘었을 경우 호출하는 형태로 만들었습니다. 

 

 

만약 중복클릭 시간동안 클릭 요청이 들어왔을 때 다른 처리를 하고싶으시다면 주석처리 되어있는 TODO 쪽을 수정하시면 됩니다.

 

 

 

개인적으로 이 방법을 사용하기도 하지만 사용자 입장에선 결국 클릭을 해도 아무런 일이 발생하지 않는 것이다 보니, 처리과정 동안 로딩을 표현해주는 것과 같이 쓰시는 것을 추천드립니다.

 

 

 

감사합니다.

 

 

 

 

 

 

예제 소스

https://github.com/tekken5953/SingleClickExam

 

GitHub - tekken5953/SingleClickExam

Contribute to tekken5953/SingleClickExam development by creating an account on GitHub.

github.com