안드로이드 소프트 키보드 숨기기

1 minute read

앱을 사용하다보면 사용자 텍스트 입력이 필요한 필드를 입력하다 필드 바깥쪽을 터치 시 소프트 키보드가 숨겨지는 모습을 볼 수 있다. 안드로이드의 경우 그런 동작이 EditText를 사용한다고 해서 자동으로 적용되지 않기 때문에 그것을 적용하는 방법을 작성해본다.

적용 전

<?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:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/tf_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="입력 필드 1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/tf_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:hint="입력 필드 2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tf_1">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Random text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tf_2" />

</androidx.constraintlayout.widget.ConstraintLayout>

EditText 바깥을 클릭해도 키보드가 사라지지 않는다.

키보드를 숨기는 방법

fun View.hideSoftKeyboard() {
    val inputMethodManager = getSystemService(context, InputMethodManager::class.java)
    inputMethodManager?.hideSoftInputFromWindow(windowToken, 0)
}

View의 확장 함수를 작성해 hideSoftInputFromWindow를 호출해 키보드를 숨길 수 있다. 이를 상위 ViewGrouponTouchEventoverride해서 클릭 이벤트를 감지해서 호출하면 적절한 상황에서 키보드를 숨길 수 있다.

class HideKeyboardConstraintLayout : ConstraintLayout {

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    private var startX = 0F
    private var startY = 0F
    private var lastClicked = 0L

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let {
            when (it.action) {
                MotionEvent.ACTION_DOWN -> {
                    Log.d("click", "${event.x}, ${event.y}")
                    startX = event.x
                    startY = event.y
                    lastClicked = System.currentTimeMillis()
                }
                MotionEvent.ACTION_UP -> {
                    Log.d("up", "${event.x}, ${event.y}")
                    val endX = event.x
                    val endY = event.y
                    val currClick = System.currentTimeMillis()
                    if (isClick(startX, startY, endX, endY, lastClicked, currClick)) {
                        performClick()
                    }
                }
            }
        }
        return super.onTouchEvent(event)
    }

    override fun performClick(): Boolean {
        this.hideSoftKeyboard()
        this.clearFocus()
        return super.performClick()
    }

    private fun isClick(
        startX: Float,
        startY: Float,
        endX: Float,
        endY: Float,
        lastClicked: Long,
        currClick: Long
    ): Boolean {
        val diffX = abs(startX - endX)
        val diffY = abs(startY - endY)
        val diffTime = currClick - lastClicked
        return diffX <= CLICK_POS_THRESHOLD && diffY <= CLICK_POS_THRESHOLD && diffTime <= CLICK_TIME_THRESHOLD
    }

    companion object {
        private const val CLICK_POS_THRESHOLD = 200
        private const val CLICK_TIME_THRESHOLD = 400L
    }
}
<?xml version="1.0" encoding="utf-8"?>
<com.mylittleproject.demoapplication.HideKeyboardConstraintLayout 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:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true"
    android:focusable="true"
    android:padding="16dp"
    tools:context=".MainActivity">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/tf_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="입력 필드 1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/tf_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:hint="입력 필드 2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tf_1">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Random text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tf_2" />

</com.mylittleproject.demoapplication.HideKeyboardConstraintLayout>

android:clickableandroid:focusabletrue로 설정한다.

적용 후

EditText 바깥 쪽을 클릭하니 키보드가 사라진다.

Comments