
Contents
ボタンが押された時にキーボードを閉じる
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でキーボードを閉じようとして詰まったところ | Memento Mori Blog