Kensuke Kousaka's Blog

Notes for Developing Software, Service.

Android Pie Viewフォーカス仕様変更について

targetSdkVersionを28以上に設定しアプリを動作させた場合、こちらに記されたように動作仕様が変更され、アプリ挙動が変わる可能性がある。手元で確認した際に、特にAndroid Pie端末でアプリを動作させた場合に、それ以前のOSバージョンを積んだ端末と比較してViewフォーカスの挙動が変化していたため、これについてまとめる。

概要

公式リファレンスでは、Viewのフォーカスの変更について以下のように記載されている。

英語...

Views with 0 area (either a width or a height is 0) are no longer focusable. Additionally, activities no longer implicitly assign initial focus in touch-mode. Instead, it is up to you to explicitly request initial focus, if desired.

日本語...

面積が0のビュー(幅または高さが0)はフォーカス不可となりました。 また、Activityはタッチモードで暗黙的に初期フォーカスを指定することはできません。代わりに、ご自身の判断で必要に応じて明示的に初期フォーカスを要求するようにしてください。

つまり、以下のようになる。

  • 暗黙的なフォーカス要求ができなくなる
  • Viewの幅や高さが0の場合、フォーカスを当てられなくなる

それでは、以下で各項目について具体的に例示する。

暗黙的なフォーカス要求ができなくなる

Oreo以前の、Activity起動時の暗黙的フォーカスは利用できなくなった。これにより、例えばレイアウト中にEditTextが存在する場合でも、targetSdkVersionが28以上かつPieでアプリを動作させている場合は自動的にフォーカスが当たってカーソルが表示されるようなことは無くなった。

targetSdkVersionが28以上かつPieでアプリを動作させる場合で、Activity起動時に任意のViewにフォーカスを当てたい場合は、フォーカス要求を実装する必要がある。

レイアウト中にEditTextがある場合の挙動は以下のようになる。

  • Oreo以前: レイアウト中にEditTextがある場合、requestFocusを実装せずともActivity起動時に自動でフォーカスが当たり、カーソルが表示される
  • targetSdkVersionが28以上かつPieの場合: レイアウト中にEditTextがあっても、Activity起動時に自動的にフォーカスが当たることは無く、カーソルは表示されない

以下レイアウトを実装しtargetSdkVersionを28に設定したアプリをOreo(8.1)、Pie(9.0)で起動すると、以下画像の挙動となる。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:text="@string/app_name"/>

    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"/>

</LinearLayout>

f:id:k3n:20181206143458g:plain
Oreo 8.1

f:id:k3n:20181206143710g:plain
Pie 9.0

Viewの幅や高さが0の場合、フォーカスを当てられなくなる

Oreo以前では、やろうと思えばheight=0dpな不可視のダミーEditTextを用意してフォーカスを当てさせることで、ユーザからの見た目上どのEditTextにもフォーカスが当たっていないように見せることもできた。

targetSdkVersionが28かつPieの場合、幅や高さが0のView(後述するが、面積が0のView)に対してフォーカスを当てることはできなくなった。これによりダミーEditTextを用いた、Activity起動時のフォーカス外しはできなくなった。

以下レイアウトを実装しtargetSdkVersionを28に設定したアプリをOreo(8.1)、Pie(9.0)で起動すると、以下画像の挙動となる。

<?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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <requestFocus/>

    <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:text="@string/app_name"/>

    <EditText
            android:id="@+id/dummy_edit_text"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            tools:ignore="Suspicious0dp"/>

    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"/>

</LinearLayout>

f:id:k3n:20181206144245g:plain
Oreo 8.1

f:id:k3n:20181206144345g:plain
Pie 9.0

なお、ConstraintLayoutのような、幅や高さをレイアウトファイル上で0dp指定し他のViewとの関係性から自身のサイズを決定するようなものについても、Viewがユーザから見えている状態(面積が0でない場合)であればフォーカスが効く。

以下レイアウトを実装しtargetSdkVersionを28に設定したアプリをPie(9.0)で起動すると、以下画像の挙動となる。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <requestFocus/>

    <TextView
            android:id="@+id/text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@id/text_view"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

</android.support.constraint.ConstraintLayout>

f:id:k3n:20181206144441g:plain
Pie 9.0