【InputMethodManager】Kotlinでキーボードを閉じる方法


ボタンが押された時にキーボードを閉じる



InputMethodManagerの使い方

Kotlinでボタンがクリックされたタイミングでソフトキーボードを閉じる方法です。

onClick()内にソフトキーボードを閉じる処理を記載します。

val button = test_button
button.setOnClickListener {
    /* ボタンクリックのタイミングでキーボードを閉じる */
    val inputManager = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    inputManager.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}

InputMethodManagerのインスタンスを取得するために、

activityを経由して Context.INPUT_METHOD_SERVICEのSystemServiceにアクセスしています。

as を使うことによって InputMethodManager 型にキャストしています。

InputMethodManager#hideSoftInputFromWindow メソッドを使い、キーボードを閉じます。

ActivityからInputMethodManagerのインスタンスを取得する際には、

そのままgetSystemService(Context.INPUT_METHOD_SERVICE)ができます。

ちなみにJavaだと以下のようなコードになります。

Button button = view.findViewById(R.id.test_button);
button.setOnClickListener(clickView -> {
    /* ボタンクリックのタイミングでキーボードを閉じる */
    InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(clickView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}


フォーカスが外れた時にキーボードを閉じる


Kotlinでフォーカスの変更通知を取得する方法です。


focusableInTouchModeを設定する


フォーカスがキーボード外に移った時にキーボードを閉じる方法です。

まずは背景にフォーカスを当てることができるように、レイアウトxmlに

android:focusableInTouchMode="true"

を設定します。

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

これをtrueに設定していないと、Kotlin側から requestFocus() をしてもフォーカスを得ることができなくなってしまいます。

LayoutやTexiViewはデフォルトでは focusableInTouchMode が false になっていてフォーカスを当てることができません。


View.requestFocus()でフォーカスを取得する


Kotlin側で背景がタッチされた時に、フォーカスを移す処理を記載します。

view.setOnTouchListener { v, event ->
    if (event.actionMasked == MotionEvent.ACTION_DOWN) {
        /* Fragmentのレイアウトがタッチされた時に、Fragment全体ににフォーカスを移す */
        view.requestFocus()
    }
    v?.onTouchEvent(event) ?: true
}

focusableInTouchMode が true であれば、requestFocus() でフォーカスを取得することができます。

※ちなみにこの処理はFragmentのライフサイクルonViewCreated()に記載しているので、

viewはFragment全体のレイアウトを指し示しています。


onFocusChangeを設定する



EditTextに onFocusChangeListener を設定して、フォーカスの移り変わりを検知できるようにします。

editText.setOnFocusChangeListener { view, hasFocus ->
    Log.d(TAG, "hasFocus : $hasFocus")
    if (!hasFocus) {
        /* 入力欄からフォーカスが外れたタイミングでキーボードを閉じる */
        val inputManager = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        inputManager.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
    }
}

第二引数のhasFocusというboolean値の変数に、

フォーカスが当たっているか(true)当たっていないか(false)が入っています。

hasFocusがfalseの時が、EditTextからフォーカスが外れたタイミングなので、

このタイミングでキーボードを閉じる処理を記載します。


ソースコード全容


最後に今回のサンプルアプリのソースコードを貼っておきます。

また今回のサンプルアプリを作るにあたり、

つまづいた点を Kotlinでキーボードを閉じようとして詰まったところ の記事にまとめました。

うまくいかないことがあればこちらも見てみてください!

参考になれば幸いです。

ご精読ありがとうございました!!


first_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <TextView
        android:id="@+id/first_fragment_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/armata"
        android:text="年齢を入力してください"
        android:textColor="#001D74"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.296" />

    <EditText
        android:id="@+id/input_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:fontFamily="@font/armata"
        android:gravity="center"
        android:inputType="number"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.483"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.373" />

    <Button
        android:id="@+id/age_category_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="#00BCD4"
        android:text="年齢区分"
        android:textColor="#FFFFFF"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.499"
        tools:ignore="MissingConstraints" />

    <TextView
        android:id="@+id/age_category_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/armata"
        android:text=""
        android:textColor="#001D74"
        android:textSize="30sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.655" />

</androidx.constraintlayout.widget.ConstraintLayout>


FirstFragment.kt

import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.first_fragment.*

class FirstFragment : Fragment() {

    companion object {
        private const val TAG = "FirstFragment"
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.first_fragment, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.setOnTouchListener { v, event ->
            if (event.actionMasked == MotionEvent.ACTION_DOWN) {
                /* Fragmentのレイアウトがタッチされた時に、Fragment全体ににフォーカスを移す */
                view.requestFocus()
            }
            v?.onTouchEvent(event) ?: true
        }

        val ageCategoryButton = age_category_button
        val editText = input_age
        editText.setOnFocusChangeListener { view, hasFocus ->
            Log.d(TAG, "hasFocus : $hasFocus")
            if (!hasFocus) {
                /* 入力欄からフォーカスが外れたタイミングでキーボードを閉じる */
                val inputManager = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                inputManager.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
            }
        }
        val ageCategoryResult = age_category_result
        ageCategoryButton.setOnClickListener {
            Log.d(TAG, "ageCategoryButton pressed!")

            /* ボタンクリックのタイミングでFragmentにフォーカスを移すことによって、キーボードを閉じる */
            view.requestFocus()

            if (TextUtils.isEmpty(editText.text.toString())) {
                /* 入力欄が空であれば何もしない */
                Log.d(TAG, "Input age is empty.")
                return@setOnClickListener
            }

            val inputAge = Integer.parseInt(editText.text.toString())
            val ageCategory = selectAgeCategory(inputAge)
            ageCategoryResult.text = ageCategory
        }
    }


    private fun selectAgeCategory(age: Int): String {
        Log.d(TAG, "Inputted age : $age")
        return when {
            age < 0       -> "不正な年齢"
            age in 0..14  -> "幼少期"
            age in 15..29 -> "青春期"
            age in 30..44 -> "朱夏期"
            age in 45..59 -> "白秋期"
            age in 60..75 -> "玄冬期"
            else          -> "高齢期"
        }
    }
}

【InputMethodManager】Kotlinでキーボードを閉じる方法」への1件のフィードバック

  1. ピンバック: 【InputMethodManager】Kotlinでキーボードを閉じようとして詰まったところ | Memento Mori Blog

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です