Instacartでは、Solve for the Customer (お客様のために問題を解決すること)は私たちの最初の最も重要な課題です。 最近、私たちはAndroidアプリのアクセシビリティを向上させ、より幅広い顧客にサービスを提供するために1ヶ月を要しました。

ナビゲーション&フォーカス

食料品の購入はかなりの数の検索を行い、店舗や「仮想通路」をブラウズし、最良のクーポンを見つけることが含まれます。blindユーザーと視覚障害のあるユーザーが自信を持ってアプリをナビゲートできるように、次の方法(戦術)を実装しました。

1.キーボードとアクセシビリティナビゲーション(TalkBack)のフォーカスが一貫している必要があります
2.新しい画面では、フォーカスは常にツールバーまたはヘッダーに表示する必要があります
3.画面のタイトルやコンテンツの説明はTalkBackで読む必要があります

キーボードとアクセシビリティのフォーカスを別々に扱う必要がある場合は、すべての画面で2つの追加UIインタラクションを設計する必要があります。 メンテナンスコストを最小限に抑えるために、キーボードとアクセシビリティの焦点を1つとして扱うことにしました。 そこで私たちは、viewに焦点を当てる簡単なアプローチから始めました。

// Intuitive Focus Extension, Kotlin, Android min 19 SDK fun View.accessibilityFullFocus() {     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)     requestFocus() }

残念ながら、これはほとんどの場合、信頼できませんでした。 最初の問題は、アクティビティライフサイクルから「非同期的に」(asynchronously)作業するアクセシビリティサービスに関連していました(つながりました)。 ActivityまたはFragment onResumeで上記のコードを呼び出すと、必ずしも機能しません。 2つ目の問題は、子ビュー(child view)は親ビュー(parent view)からフォーカスを「盗む」(steal)ことがあります。

たとえば、Toolbar.setNavigationOnClickListenerが呼び出された場合、ツールバーはフォーカスを失います。 残念なことに、ツールバーにフォーカスを当てる最も信頼性の高い方法はそれほどではありませんでした。 以下は簡単なコードサンプルです。

// Sample using RxJava 1.x, Kotlin
var offSwitch = false
Observable
        .interval(0, 100L, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .takeIf { !offSwitch }
        .subscribe {
            // try to focus every 100 milliseconds until the view or any of its children is focused
            view.accessibilityFullFocus()
            offSwitch = view.isAccessibilityFocused || view.hasAccessibilityFocusedChild
        }

1つの興味深い例外は、別々のビューにアクセシビリティとキーボードのフォーカスがあることを決めたとき、インプットフィールドを持つダイアログでした。 インプットフィールドにキーボードのフォーカスを置くと、ダイアログが表示されるとすぐにユーザーが入力を提供することができました。 同時に、アクセシビリティの焦点は、ダイアログが開始されたときにタイトルが発表され、視覚障害のあるユーザーがダイアログタイトルとフィールドの間にある入力指示を見逃すことはありません。

アクセシビリティフォーカスはダイアログタイトルにあり、キーボードフォーカスはインプットフィールドにあります。

コミュニケーションの進捗

Instacartのアプリ画面のほとんどはネットワーク操作を必要とし、ロードに時間がかかります。 TalkBackユーザーを支援するために「Xが読み込まれています」「Yが読み込まれました」と音声メッセージでエラーが発生したため、ネットワーク操作の進捗状況がアナウンスされました。

一部の画面では、ネットワークリクエストが多数発生し、情報の一部が表示され、情報が入ると更新されます。古いメッセージが途中で止まるので、アナウンスが速くなり、次々と見えなくなります。 これを避けるために、1秒のデバウンスを持つキュー(queue)を実装しました(2つのメッセージが1秒以内にキューに入れられた場合、最初のメッセージは削除されます)。

コントラスト

ハイコントラストモードが無効(左)および有効(右)の画面

テキストと背景とのコントラストは、低視力のユーザーにとって重要です。 WCAGコントラスト最小達成基準は、テキストと背景の間すべての画面のレビューとカスタマイズを避けるため、ハイコントラストモードを実装し、サインアップやユーザーアカウントの設定時に顕著なオプトインモードを導入しました。 ハイコントラストモードでは、明るいテキストの色は純粋な白になり、すべての暗い色は純粋な黒に切り替わります。 アクション可能なビュー、ツールバー、およびその他の主要なナビゲーション要素のためのテーマ設定メカニズムをバックエンドで既に使用していました。 高コントラストの色をテキストに適用するために、アプリケーションのすべてのTextViewをカスタムテキストビューに置き換えました。

// Kotlin, Android min 19 SDK 

private enum class Adjustment {
    DARKEN,
    LIGHTEN,
    NONE
}

fun Context.adjustTextColor(color: Int, isHighContrastEnabled: Boolean): Int {
    if (isHighContrastEnabled) {
        return color
    }
    return when(checkAdjustment(color)) {
        Adjustment.DARKEN -> Color.BLACK
        Adjustment.LIGHTEN -> Color.WHITE
        Adjustment.NONE -> color
    }
}

fun Context.adjustTextColor(color: ColorStateList, isHighContrastEnabled: Boolean): ColorStateList {
    return when (checkAdjustment(color.defaultColor)) {
        Adjustment.DARKEN -> ColorStateList.valueOf(Color.BLACK)
        Adjustment.LIGHTEN -> ColorStateList.valueOf(Color.WHITE)
        Adjustment.NONE -> color
    }
}

private fun isContrastTooSmall(color: Int, bgColor: Int): Boolean {
    // WCAG 2.0 level AA requires a contrast ratio of 4.5:1
    return ColorUtils.calculateContrast(color, bgColor) < 4.7f
}

private fun checkAdjustment(color: Int): Adjustment {
    val luminance = ColorUtils.calculateLuminance(color)
    if (luminance == 1.0 || luminance == 0.0) {
        return Adjustment.NONE
    }

    if (luminance >= 0.5 && isContrastTooSmall(color, Color.BLACK)) {
        return Adjustment.LIGHTEN
    }

    if (luminance < 0.5 && isContrastTooSmall(color, Color.WHITE)) {
        return Adjustment.DARKEN
    }
    return Adjustment.NONE
}

結論とその他のリソース

上記は、私たちがAndroidアプリケーションをより使いやすくするために適用したいくつかの設計上の決定を要約したものです。 この記事では、このテーマについてのより広いディスカッションと知識の共有を促進することを目指しています。

迅速に立ち上げ、有効であると証明されたリソース:

Renato IwashimaによるアクセシブルなAndroidアプリケーションの開発
Ataul Munimによる視覚障害ユーザー用のAndroidアプリの設計
Renato Iwashimaによるテキストインプットアクセシビリティ

特に、昨年の夏の電子商取引業界では、ウェブサイトのアクセシビリティに関連した訴訟が増加しています。私たちはトピックがより顕著になることを期待しています。

脚注
¹コンテキストでは、ツールバーを通常のビューとして使用しています。これはフラグメントやビューグループ内にあることが多く、ツールバーの新しいビューがフォアグラウンドになるたびにアクティビティにsetSupportActionBarを設定しません。

タイトル:A month of Android Accessibility

作者:Maksim Golivkin

原文URL: https://tech.instacart.com/a-month-of-android-accessibility-1032e2566b25

今すぐシェアしよう!
今すぐシェアしよう!