アプリのユーザー補助機能の改善に関する原則

ユーザー補助機能のニーズは、Android デバイスを使用するユーザーによって異なります。同じユーザー補助機能のニーズを持つユーザーを支援するために、Android フレームワークには、ユーザー補助サービスを作成する機能が用意されています。これは、対象ユーザーにアプリのコンテンツを提示し、ユーザーの代わりにアプリを操作するものです。

Android では、次のようなシステムのユーザー補助サービスを提供しています。

  • TalkBack: 視力の弱いユーザーや目の不自由なユーザーをサポートします。合成音声でコンテンツを知らせ、ユーザーの操作に応じてアプリでアクションを実行します。
  • スイッチ アクセス: 運動障がいのあるユーザーをサポートします。インタラクティブな要素をハイライト表示し、ユーザーのボタン押下に応じてアクションを実行します。1 つまたは 2 つのボタンを使用するだけでデバイスを制御できます。

ユーザー補助機能を必要とするユーザーがアプリを快適に利用できるように、このページで説明されているおすすめの方法に沿ったアプリを作成する必要があります。おすすめの方法は、アプリのユーザー補助機能を強化するで説明した重要なガイドラインに基づいています。

アプリのユーザー補助機能を改善するには、次のおすすめの方法を参考にしてください。

要素にラベルを付ける
アプリ内で操作対象になる有用な各 UI 要素について、その内容と目的をユーザーが理解できるようにする必要があります。
システム ウィジェットを使用または拡張する
独自のカスタムビューを作成するのではなく、フレームワークに含まれるビュー要素から作成します。フレームワークのビュークラスとウィジェット クラスは、アプリに必要なほとんどのユーザー補助機能をすでに提供しています。
色以外の手がかりも取り入れる
ユーザーが UI の要素の種類を明確に区別できるようにする必要があります。そのためには、色だけでなく、パターンや位置によって、こうした区別を表します。
メディア コンテンツのユーザー補助機能を強化する
アプリの動画や音声コンテンツに説明を追加して、コンテンツを消費するユーザーが視覚的な手がかりや音声の手がかりだけに頼らないでもすむようにします。

要素にラベルを付ける

アプリ内の操作対象の UI 要素ごとに、有用でわかりやすいラベルをユーザーに提供することが重要です。各ラベルで、その特定の要素の意味と目的を説明する必要があります。TalkBack などのスクリーン リーダーは、こうしたサービスに頼るユーザーにそのラベルを読み上げることができます。

通常各 UI 要素の説明は、その要素が含まれるレイアウト リソース ファイルに指定します。アプリのユーザー補助機能を強化するガイドで説明するように、通常は contentDescription 属性を使ってラベルを指定しますが、以下のセクションで説明するように、ほかにもいくつか、ラベルの指定についておすすめのテクニックがあります。

編集可能な要素

EditText オブジェクトのように編集可能な要素にラベルを付ける場合、その要素そのものへの有効な入力テキスト例を、スクリーン リーダーが利用できるようにするだけでなく、表示しておくと便利です。その状況では、次のスニペットに示すように、android:hint 属性を使用できます。

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
<EditText
   android:id="@+id/addressLine2"
   android:hint="@string/aptSuiteBuilding" ... />

この場合、View オブジェクトの android:labelFor 属性には EditText 要素の ID を設定しておきます。詳しくは、一方が他方の説明をする要素ペアのラベル付けについての説明をご覧ください。

一方が他方の説明をする要素のペア

ある EditText 要素に対して、その EditText 要素内にユーザーが入力する必要のあるコンテンツについて説明する View オブジェクトが対応していることはよくあります。Android 4.2(API レベル 17)以上を搭載するデバイスでは、こうした関係を View オブジェクトの android:labelFor 属性に設定して示すことができます。

このような要素ペアのラベル付けの例を、次のスニペットに示します。


<!-- Label text for en-US locale would be "Username:" -->
<TextView
   android:id="@+id/usernameLabel" ...
   android:text="@string/username"
   android:labelFor="@+id/usernameEntry" />

<EditText
   android:id="@+id/usernameEntry" ... />

<!-- Label text for en-US locale would be "Password:" -->
<TextView
   android:id="@+id/passwordLabel" ...
   android:text="@string/password
   android:labelFor="@+id/passwordEntry" />

<EditText
   android:id="@+id/passwordEntry"
   android:inputType="textPassword" ... />

コレクション内の要素

コレクションの要素にラベルを指定する場合、各ラベルは固有である必要があります。 そうすることで、システムのユーザー補助サービスがラベルを読み上げる際、画面上の要素を 1 つずつ正確に参照できます。こうした対応関係により、ユーザーは UI の確認が一巡したことや、以前に確認した要素にまたフォーカスを移動したことを判断できます。

特に RecyclerView オブジェクトのように、再利用するレイアウト内の要素には、追加のテキストやコンテキスト情報を含めて、各子要素が一意に識別できるようにする必要があります。

そのためには、次のコード スニペットに示すように、コンテンツの説明をアダプター実装の一部として設定します。

Kotlin

data class MovieRating(val title: String, val starRating: Integer)

class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {

    class MyRatingViewHolder(val ratingView: ImageView) :
            RecyclerView.ViewHolder(ratingView)

    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"
    }
}

Java

public class MovieRating {
    private String title;
    private int starRating;
    // ...
    public String getTitle() { return title; }
    public int getStarRating() { return starRating; }
}

public class MyMovieRatingsAdapter
        extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> {
    private MovieRating[] myData;

    public static class MyRatingViewHolder extends RecyclerView.ViewHolder {
        public ImageView ratingView;
        public MyRatingViewHolder(ImageView iv) {
            super(iv);
            ratingView = iv;
        }
    }

    @Override
    public void onBindViewHolder(MyRatingViewHolder holder, int position) {
        MovieRating ratingData = myData[position];
        holder.ratingView.setContentDescription("Movie " + position + ": " +
                ratingData.getTitle() + ", " + ratingData.getStarRating() +
                " stars")
    }
}

関連コンテンツのグループ

曲の詳細やメッセージの属性など、自然なグループを構成する複数の UI 要素をアプリで表示する場合、通常 ViewGroup のサブクラスであるコンテナ内にそれらの要素を配置します。このコンテナ オブジェクトの android:screenReaderFocusable 属性を true に設定し、各内部オブジェクトの android:focusable 属性を false に設定します。そうすることで、内部に含まれるコンテンツの説明を、ユーザー補助サービスが続けて一度に読み上げて紹介することができます。関連要素をこうして統合すると、補助サービスのユーザーが画面上にある情報を効率よく発見できるようになります。

次のスニペットには互いに関連するコンテンツが含まれているので、ConstraintLayout のインスタンスであるコンテナ要素の android:screenReaderFocusable 属性が true に、内部要素である TextViewandroid:focusable 属性が false に設定されています。

<!-- In response to a single user interaction, accessibility services announce
     both the title and the artist of the song. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true">

    <TextView
        android:id="@+id/song_title" ...
        android:focusable="false"
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"
        android:focusable="false"
        android:text="@string/my_songwriter" />
</ConstraintLayout>

ユーザー補助サービスが内部要素の説明を一度に読み上げるので、各説明は要素の意味を伝える一方で、できる限り短くすることが重要です。

カスタム グループラベル

必要に応じて、グループそのもののコンテンツの説明を提供することにより、グループの内部要素の説明について、プラットフォームでのデフォルトのグループ設定や順序をオーバーライドできます。

次のスニペットにカスタマイズされたグループの説明の例を示します。

<!-- In response to a single user interaction, accessibility services
     announce the custom content description for the group. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true"
    android:contentDescription="@string/title_artist_best_song">

    <TextView
        android:id="@+id/song_title" ...

        <!-- Content ignored by accessibility services -->
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"

        <!-- Content ignored by accessibility services -->
        android:text="@string/my_songwriter" />
</ConstraintLayout>

ネストされたグループ

アプリのインターフェースに、フェスティバル イベントの日別のリストのように、多次元の情報がある場合は、内側のグループ コンテナの android:screenReaderFocusable 属性を使用します。このラベル付け方式により、画面上のコンテンツを知らせるのに必要な読み上げの回数と、各読み上げの長さのバランスをとることができます。

次のコード スニペットでは、外側のグループ内で内側のグループをラベル付けする方法の一例を示します。

<!-- In response to a single user interaction, accessibility services
     announce the events for a single stage only. -->
<ConstraintLayout
    android:id="@+id/festival_event_table" ... >
    <ConstraintLayout
        android:id="@+id/stage_a_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage A. -->

    </ConstraintLayout>
    <ConstraintLayout
        android:id="@+id/stage_b_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage B. -->

    </ConstraintLayout>
</ConstraintLayout>

テキスト内の見出し

一部のアプリでは画面上に表示するテキスト グループの概要を、見出しを使って示すことがあります。特定の View 要素が見出しを表す場合、その要素の android:accessibilityHeading 属性を true に設定することでそうした意図をユーザー補助サービスに示すことができます。

補助サービスのユーザーは、段落間や単語間ではなく、見出し間を移動するように選択できます。このように柔軟性が増したことで、テキスト ナビゲーションの利便性が向上します。

ユーザー補助ペインのタイトル

Android 9(API レベル 28)以上では、画面のペインにユーザー補助に利用できるタイトルを提供できます。ユーザー補助機能にとってペインは、フラグメントのコンテンツのように、ウィンドウ内で視覚上区分けされた部分です。ペインにおけるウィンドウのような動作をユーザー補助サービスが理解するには、アプリのペインにわかりやすいタイトルを付ける必要があります。それにより、ユーザー補助サービスでは、ペインの外観やコンテンツが変更されたときに、詳細な情報をユーザーに提供できます。

ペインのタイトルを指定するには、次のスニペットに示すように、android:accessibilityPaneTitle 属性を使用します。

<!-- Accessibility services receive announcements about content changes
     that are scoped to either the "shopping cart view" section (top) or
     "browse items" section (bottom) -->
<MyShoppingCartView
     android:id="@+id/shoppingCartContainer"
     android:accessibilityPaneTitle="@string/shoppingCart" ... />

<MyShoppingBrowseView
     android:id="@+id/browseItemsContainer"
     android:accessibilityPaneTitle="@string/browseProducts" ... />

装飾的要素

UI 内のある要素が視覚的な間隔をあけるため、または見た目のためにのみ存在する場合、その android:contentDescription 属性を "null" に設定してください。

Android 4.1(API レベル 16)以上を搭載するデバイスのみをサポートするアプリの場合は、代わりにこうした純粋に装飾的な要素の android:importantForAccessibility 属性を "no" に設定できます。

システム ウィジェットを拡張する

キーポイント: アプリの UI を設計するときは、Android のクラス階層のできるだけ下位にあるシステム提供のウィジェットを使用または拡張します。システム提供のウィジェットには、アプリが必要とするほとんどのユーザー補助機能がすでに用意されています。こうしたシステム提供のウィジェットを拡張する方が、より汎用的な ViewViewCompatCanvasCanvasCompat クラスから独自のウィジェットを作成するよりも簡単です。

高度にカスタマイズされた機能やゲームレベルで必要になるなど、View または Canvas を直接拡張する必要がある場合は、カスタムビューのユーザー補助機能を強化するをご覧ください。

ここでは、TriSwitch という特別なタイプの Switch を実装する方法について説明します。TriSwitch オブジェクトは、Switch オブジェクトと同じように機能しますが、TriSwitch の各インスタンスで、ユーザーが選択可能な 3 つの状態を切り替えることができる点が異なります。

クラス階層の下位から拡張する

Switch オブジェクトは、そのクラス階層内のフレームワーク UI クラスを継承します。

View
↳ TextView
  ↳ Button
    ↳ CompoundButton
      ↳ Switch

新しい TriSwitch クラスを作成する場合、Switch クラスから直接拡張することをおすすめします。直接拡張すれば、Android のユーザー補助フレームワークにより、TriSwitch クラスに必要なほとんどのユーザー補助機能が提供されます。

  • ユーザー補助アクション: TriSwitch オブジェクトで実行される各ユーザー入力をユーザー補助サービスがエミュレートする方法をシステムに通知します (View から継承)。
  • ユーザー補助イベント: 画面が更新またはアップデートされるときに TriSwitch オブジェクトの外観を変更できるあらゆる方法についてユーザー補助サービスに通知します(View から継承)。
  • 特性: 表示されるテキストの内容など、各 TriSwitch オブジェクトの詳細(TextView から継承)。
  • 状態に関する情報: 「オン」、「オフ」など、TriSwitch オブジェクトの現在の状態に関する説明(CompoundButton から継承)。
  • 状態の説明テキスト: 各状態が表す内容に関するテキストベースの説明(Switch から継承)。

Switch とそのスーパークラスから集約した動作は、ほぼ TriSwitch オブジェクトに求められる動作です。したがって、実装では、選択可能な状態の数を 2 から 3 に増やすことに集中できます。

カスタム イベントを定義する

システム ウィジェットを拡張すると、ユーザーによるそのウィジェットの操作方法について変更が生じる可能性が高まります。ユーザーがウィジェットを直接操作しているかのように、ユーザー補助サービスによってアプリのウィジェットが更新されるよう、こうした操作の変更を定義することが重要です。

一般的なガイドラインとしては、オーバーライドするビューベースのコールバックごとに、ViewCompat.replaceAccessibilityAction() をオーバーライドして、対応するユーザー補助アクションを再定義する必要もあります。 アプリのテストでは、ViewCompat.performAccessibilityAction() を呼び出して、このような再定義したアクションの動作を検証できます。

TriSwitch オブジェクトに対するこの原則の応用

通常の Switch オブジェクトとは異なり、TriSwitch オブジェクトをタップすると、3 つの状態が繰り返されます。したがって、対応する ACTION_CLICK のユーザー補助アクションを更新する必要があります。

Kotlin

class TriSwitch(context: Context) : Switch(context) {
    // 0, 1, or 2.
    var currentState: Int = 0
        private set

    init {
        updateAccessibilityActions()
    }

    private fun updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label) {
            view, args -> moveToNextState()
        })
    }

    private fun moveToNextState() {
        currentState = (currentState + 1) % 3
    }
}

Java

public class TriSwitch extends Switch {
    // 0, 1, or 2.
    private int currentState;

    public int getCurrentState() {
        return currentState;
    }

    public TriSwitch() {
        updateAccessibilityActions();
    }

    private void updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label, (view, args) -> moveToNextState());
    }

    private void moveToNextState() {
        currentState = (currentState + 1) % 3;
    }
}

色以外の手がかりも取り入れる

色覚障がいのあるユーザーをサポートするには、アプリ画面内の UI 要素を区別するのに、色以外の手がかりを使用してください。そのテクニックとして、形やサイズを変える、テキストまたは視覚的なパターンを示す、音声またはタップ(触覚)に基づくフィードバックを追加する方法などにより、要素を区別します。

図 1 に、あるアクティビティの 2 つのバージョンを示します。一方のバージョンでは、ワークフロー内の可能な 2 つのアクションを、色だけで区別しています。もう一方のバージョンでは、おすすめの方法を取り入れて、色だけでなく、形とテキストによって、2 つのアクションの違いを強調しています。

図 1: 色だけ(左)と色、形、テキスト(右)を使った UI 要素の作成例

メディア コンテンツのユーザー補助機能を強化する

動画クリップや音声録音などのメディア コンテンツを含むアプリを開発する場合、そうしたコンテンツを把握する際のさまざまなユーザー補助のニーズに応じるサポートを試みてください。具体的には、以下を行うことをおすすめします。

  • メディアの一時停止または停止、音量の変更、字幕(キャプション)の切り替えをユーザーが行えるようにするコントロールを含めます。
  • ワークフローの完了に不可欠な情報を動画が提示する場合、文字起こしのように、同じ内容を代替形式で提供します。

参考情報

アプリのユーザー補助機能を強化する方法について詳しくは、以下の参考情報をご覧ください。

コードラボ

ブログ投稿