Androidアプリで起動時のEditTextへのフォーカスを外す方法【Java】

起動時のEditTextへのフォーカスを外す方法
概要
AndroidではActivity起動時に画面内最初のEditTextにフォーカスされます。便利な機能ですが自動でフォーカスしてほしくない場合もあります。
この自動フォーカスを防ぐ方法ともっと詳しく知っておきたい方のためにAndroidのフォーカスの仕組みをまとめます。
他のViewにフォーカスを当てたい場合

xmlで指定する方法
他にフォーカスを当てたいViewがある場合には、そのViewにrequestFocusを追加します。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/sample_editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目1"
/>
<EditText
android:id="@+id/sample_editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目2">
<requestFocus/>
</EditText>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="ボタン"
/>
</LinearLayout>
この例ではEditText2つとButton1つがあります。特に何もせずに起動すると入力項目1のEditTextにフォーカスされます。
これを入力項目2のほうにフォーカスさせたいというような場合、2つ目のEditTextの中にrequestFocusを追加することで起動時に入力項目2のほうにフォーカスされ、入力項目1からはフォーカスが外れます。
コードで指定する場合
xmlで指定するのと同じことをJavaコードでやる場合には以下のようになります。
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText sample2 = findViewById(R.id.sample_editText2);
sample2.requestFocus();
}
}
入力項目2のEditTextからrequestFocus()メソッドを呼ぶことで入力項目1のフォーカスが外れて入力項目2にフォーカスされます。
単にフォーカスを外したい場合

xmlで指定する方法
以下の例では親要素のLinearLayoutのandroid:focusableInTouchModeをtrueにしています。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/linearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:focusableInTouchMode="true">
<EditText
android:id="@+id/sample_editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目1"
/>
<EditText
android:id="@+id/sample_editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目2">
</EditText>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="ボタン"
/>
</LinearLayout>
こうすることで入力項目1より先に親要素のLinearLayoutにフォーカスされることになり、結果的に入力項目1からフォーカスが外れます。
他には空の要素を追加するという方法もあります。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/linearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusableInTouchMode="true" />
<EditText
android:id="@+id/sample_editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目1"
/>
<EditText
android:id="@+id/sample_editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="入力項目2">
</EditText>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="ボタン"
/>
</LinearLayout>
空のLinearLayoutを作りandroid:focusableInTouchModeをtrueにしています。
これも同じくEditTextよりも先に空のLinearLayoutにフォーカスされるので結果的に入力項目1からフォーカスが外れます。当然この空要素はEditTextよりも上に配置されていないと意味がないので注意してください。
コードで指定する場合
xmlで指定するのと同じことをJavaコードでやる場合は以下のようになります。
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout linearLayout = findViewById(R.id.linearLayout);
linearLayout.setFocusableInTouchMode(true);
}
}
親要素のLinearLayoutにsetFocusableInTouchMode()メソッドでtrueを渡しています。
Androidのフォーカスの仕組み
タッチモードと非タッチモード
Androidにはタッチモードとタッチモードではないモード(非タッチモード)が用意されています。
タッチモードとは画面タッチで操作するモードで、非タッチモードとはトラックボール、十字キー(方向キー)、キーボードのTABキーなどで操作するモードです。画面内の部品にフォーカスを当てるという点において、これらのモードには微妙な違いがあります。
例えば、EditTextは文字を入力するためにタッチモードでも非タッチモードでもフォーカスを当てて操作することになるので2つのモードに違いはありません。しかし、Buttonは非タッチモードではEnterキー(決定キー)を押すためにフォーカスを当てる必要がありますが、タッチモードではタッチによってButtonの処理が呼び出されるのでフォーカスを当てる必要はありません。
この違いに対応するためにfocusableという設定とfocusableInTouchModeという設定の2つが用意されています。
focusableとfocusableInTouchMode
focusableとはフォーカスを当てることができるかという設定です。focusableのデフォルト値は以下のようになっています。
LinearLayout | false |
---|---|
TextView | false |
CheckBox | true |
SeekBar | true |
EditText | true |
Button | true |
入力項目として使うようなViewはフォーカスが当てられるようにtrue、LinearLayoutやTextViewなどの入力に関係のないViewはフォーカスを当てる必要がないのでfalseとなっています。
対して、focusableInTouchModeとはタッチモードのときにフォーカスを当てられるかという設定です。focusableInTouchModeのデフォルト値は以下のようになっています。
LinearLayout | false |
---|---|
TextView | false |
CheckBox | false |
SeekBar | false |
EditText | true |
Button | false |
入力項目として使うViewの中でもタッチするだけで処理できるものはfalseになっています。
Activity起動時にEditTextに自動でフォーカスされるのは、画面内で一番上にあるfocusableInTouchModeがtrueのViewを検索しているからです。したがって、EditTextよりも優先されるfocusableInTouchModeがtrueのViewを用意してあげるとEditTextからのフォーカスを外すことができます。
ちなみに、ScrollViewなどを用いてActivity起動時にEditTextが画面外になるような構造の場合はそもそも自動でフォーカスされることはありません。
投稿されたコメント一覧