Zwiększanie dostępności widoków niestandardowych

Jeśli Twoja aplikacja wymaga komponent widoku niestandardowego, musisz zwiększyć dostępność widoku. Wykonując te czynności, możesz poprawić o ułatwieniach dostępu opisanych na tej stronie:

  • Obsługuj kliknięcia kontrolera kierunkowego.
  • Wdrażanie metod interfejsu Accessibility API.
  • Wyślij AccessibilityEvent typowe obiekty widoku niestandardowego.
  • Wypełnij pola AccessibilityEvent i AccessibilityNodeInfo z punktu widzenia Twojej firmy.

Obsługa kliknięć kontrolera kierunkowego

Na większości urządzeń kliknięcie widoku za pomocą kontrolera kierunkowego powoduje wysłanie KeyEvent z KEYCODE_DPAD_CENTER do bieżącego widoku. Wszystkie standardowe uchwyty widoków danych na Androidzie KEYCODE_DPAD_CENTER. Podczas tworzenia niestandardowego View upewnij się, że to zdarzenie ma taki sam skutek jak dotknięcie widoku na ekranie dotykowym.

Twój niestandardowy element sterujący musi traktować element KEYCODE_ENTER tym samym co KEYCODE_DPAD_CENTER. Umożliwia korzystanie z pełnej klawiatury dla użytkowników.

Wdrażanie metod interfejsu Accessibility API

Zdarzenia ułatwień dostępu to wiadomości na temat interakcje z interfejsem wizualnym aplikacji; Te wiadomości są obsługiwane przez usługi ułatwień dostępu, które obsługują wykorzystać informacje z tych zdarzeń do wygenerowania dodatkowych informacji zwrotnych i promptów. Ułatwienia dostępu metody są częścią View i View.AccessibilityDelegate zajęcia. Dostępne metody:

dispatchPopulateAccessibilityEvent()
System wywołuje tę metodę, gdy widok niestandardowy generuje zdarzenie związane z ułatwieniami dostępu. Domyślny implementacja tej metody wywołuje onPopulateAccessibilityEvent() dla tego widoku danych a potem metodę dispatchPopulateAccessibilityEvent() dla każdego elementu podrzędnego widok.
onInitializeAccessibilityEvent()
System wywołuje tę metodę, aby uzyskać dodatkowe informacje o stanie widoku poza treści tekstowe. Jeśli Twój widok niestandardowy zapewnia bardziej interaktywną kontrolę niż prosty widok TextView lub Button, zastąp tę metodę i ustawić dodatkowe informacje o widoku, takie jak typ pola hasła, pole wyboru typu lub stany, które zawierają interakcję użytkownika z wydarzeniem lub związane z nim opinie – za pomocą tego . Jeśli zastąpisz tę metodę, wywołaj jej superimplementację i zmodyfikuj tylko właściwości które nie są ustawione przez klasę nadrzędną.
onInitializeAccessibilityNodeInfo()
Ta metoda udostępnia usługom ułatwień dostępu informacje o stanie widoku. domyślna implementacja View ma standardowy zestaw właściwości widoku, ale jeśli widok niestandardowy zapewnia interaktywną kontrolę wykraczającą poza prosty widok TextView lub Button, zastąp tę metodę i ustaw dodatkowe informacje o widoku do obiektu AccessibilityNodeInfo obsługiwanego przez tę metodę.
onPopulateAccessibilityEvent()
Ta metoda ustawia głosowe prompty tekstowe (AccessibilityEvent) na urządzeniu widok. Nazywa się ją też, jeśli widok jest elementem podrzędnym widoku, który generuje ułatwienia dostępu. .
onRequestSendAccessibilityEvent()
System wywołuje tę metodę, gdy element podrzędny Twojego widoku generuje AccessibilityEvent Ten krok pozwala rodzicowi wyświetlać informacje o zmianach w ułatwieniach dostępu wydarzenie z dodatkowymi informacjami. Zastosuj tę metodę tylko wtedy, gdy widok niestandardowy może zawierać czy widok nadrzędny może zawierać informacje kontekstowe do ułatwień dostępu, zdarzenie, które jest przydatne w usługach ułatwień dostępu.
sendAccessibilityEvent()
System wywołuje tę metodę, gdy użytkownik wykonuje działanie związane z wyświetleniem. Zdarzenie jest sklasyfikowane jako typ działania użytkownika, np. TYPE_VIEW_CLICKED. Ogólnie rzecz biorąc, AccessibilityEvent, gdy zmieni się zawartość widoku niestandardowego.
sendAccessibilityEventUnchecked()
Ta metoda jest używana, gdy kod kierunkowy musi bezpośrednio kontrolować sprawdzanie włączone ułatwienia dostępu na urządzeniu (AccessibilityManager.isEnabled()). Jeśli wdrożysz tę metodę, wykonaj wywołanie tak, jakby były włączone ułatwienia dostępu, niezależnie od ustawienia systemu. Zwykle nie musisz implementować tej metody w przypadku widoku niestandardowego.

Aby zapewnić obsługę ułatwień dostępu, zastąp i wdróż powyższe metody ułatwień dostępu bezpośrednio w do klasy widoku niestandardowego.

W przypadku klasy widoku niestandardowego zaimplementuj przynajmniej te metody ułatwień dostępu:

  • dispatchPopulateAccessibilityEvent()
  • onInitializeAccessibilityEvent()
  • onInitializeAccessibilityNodeInfo()
  • onPopulateAccessibilityEvent()

Więcej informacji o wdrażaniu tych metod znajdziesz w sekcji wypełnianie zdarzeń ułatwień dostępu.

Wysyłaj zdarzenia dotyczące ułatwień dostępu

W zależności od specyfiki widoku niestandardowego konieczne może być przesłanie AccessibilityEvent obiektów w różnych momentach lub w przypadku zdarzeń, które nie są obsługiwane domyślnie implementacji. Klasa View udostępnia domyślną implementację tych zdarzeń. typy:

.

Ogólnie rzecz biorąc, musisz wysyłać AccessibilityEvent za każdym razem, gdy treść Twojego dostosowania zobacz zmiany. Jeśli na przykład wdrażasz niestandardowy pasek z suwakiem, który umożliwia użytkownikowi wybranie po naciśnięciu klawisza strzałki w lewo lub w prawo, widok niestandardowy musi emitować zdarzenie TYPE_VIEW_TEXT_CHANGED za każdym razem, gdy zmienia się wartość suwaka. Poniższa próbka kodu pokazuje, jak można wykorzystać Metoda sendAccessibilityEvent(), aby zgłosić to zdarzenie.

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when(keyCode) {
        KeyEvent.KEYCODE_DPAD_LEFT -> {
            currentValue--
            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)
            true
        }
        ...
    }
}

Java

@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
        currentValue--;
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
        return true;
    }
    ...
}

Wypełnianie zdarzeń ułatwień dostępu

Każdy element AccessibilityEvent ma zestaw wymaganych właściwości opisujących bieżącą stanu widoku. Właściwości te obejmują nazwę klasy widoku, zawartość opis i stan zaznaczenia. Opisujemy właściwości wymagane w przypadku poszczególnych typów zdarzeń. w AccessibilityEvent dokumentacji referencyjnej.

Implementacja View podaje wartości domyślne dla tych właściwości wymagane. Wiele z tych wartości, w tym nazwa klasy i sygnatura czasowa zdarzenia, jest jest podawany automatycznie. Jeśli tworzysz komponent widoku niestandardowego, musisz podać informacje dotyczące treści i cech danego widoku. Te informacje wystarczy umieścić na przycisku i mogą zawierać dodatkowe informacje o stanie, które chcesz dodać do zdarzenia.

Użyj onPopulateAccessibilityEvent() oraz onInitializeAccessibilityEvent() do wypełniania lub modyfikowania informacji w AccessibilityEvent. Użyj Metoda onPopulateAccessibilityEvent() służąca do dodawania lub modyfikowania tekstu treść wydarzenia, która jest przekształcana w dźwiękowe prompty przez usługi ułatwień dostępu takie jak TalkBack. Aby wypełnić dodatkowe pola, użyj metody onInitializeAccessibilityEvent() informacje o zdarzeniu, np. stan wyboru widoku.

Dodatkowo zaimplementuj onInitializeAccessibilityNodeInfo() . Usługi ułatwień dostępu używają obiektów AccessibilityNodeInfo wypełnianych przez ten atrybut metoda badania hierarchii widoków, która generuje zdarzenie ułatwień dostępu po jego otrzymaniu. i przekazywać użytkownikom odpowiednie opinie.

Poniższy przykładowy kod pokazuje, jak zastąpić te 3 metody w widoku:

Kotlin

override fun onPopulateAccessibilityEvent(event: AccessibilityEvent?) {
    super.onPopulateAccessibilityEvent(event)
    // Call the super implementation to populate its text for the
    // event. Then, add text not present in a super class.
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        event?.text?.add(text)
    }
}

override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) {
    super.onInitializeAccessibilityEvent(event)
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event?.isChecked = isChecked()
}

override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
    super.onInitializeAccessibilityNodeInfo(info)
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info?.isCheckable = true
    info?.isChecked = isChecked()
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        info?.text = text
    }
}

Java

@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
    super.onPopulateAccessibilityEvent(event);
    // Call the super implementation to populate its text for the
    // event. Then, add the text not present in a super class.
    // You typically only need to add the text for the custom view.
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        event.getText().add(text);
    }
}

@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
    super.onInitializeAccessibilityEvent(event);
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event.setChecked(isChecked());
}

@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    super.onInitializeAccessibilityNodeInfo(info);
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info.setCheckable(true);
    info.setChecked(isChecked());
    // You typically only need to add the text for the custom view.
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        info.setText(text);
    }
}

Te metody możesz wdrożyć bezpośrednio w klasie widoku niestandardowego.

Zadbaj o niestandardowy kontekst ułatwień dostępu

Usługi ułatwień dostępu mogą sprawdzać hierarchię widoku, który zawiera komponent interfejsu użytkownika które generuje zdarzenie ułatwień dostępu. Dzięki temu usługi ułatwień dostępu mogą zapewniać które pomagają użytkownikom.

W niektórych przypadkach usługi ułatwień dostępu nie mogą uzyskać odpowiednich informacji z widoku. w hierarchii. Przykładem może być niestandardowy element sterujący interfejsu, który zawiera co najmniej 2 osobne klikalne obszary, takie jak elementy sterujące kalendarza. W takim przypadku usługi nie są w stanie zapewnić wystarczająco bo klikalne podsekcje nie należą do hierarchii widoków.

Rysunek 1. Niestandardowy widok kalendarza z elementami umożliwiającymi wybór dnia.

W przykładzie na rys. 1 cały kalendarz jest zaimplementowany jako jeden widok, więc ułatwienia dostępu usługi otrzymują za mało informacji o zawartości wyświetlenia i wyborze użytkownika w widoku, chyba że deweloper poda dodatkowe informacje. Jeśli na przykład użytkownik kliknie w dniu oznaczonym etykietą 17 system ułatwień dostępu otrzymuje tylko informacje o opisie. i mają pełną kontrolę nad kalendarzem. W takim przypadku usługa ułatwień dostępu TalkBack informuje „Kalendarz” lub „Kalendarz kwietniowy”, a użytkownik nie wie, jaki dzień zostaje wybrany.

Aby zapewnić odpowiednie informacje kontekstowe dla usług ułatwień dostępu w takich sytuacjach, pozwala określić hierarchię widoku wirtualnego. Hierarchia widoków wirtualnych to zapewniają deweloperom aplikacji uzupełniającą hierarchię widoków usług ułatwień dostępu, ściśle pasuje do informacji na ekranie. Dzięki temu usługi ułatwień dostępu przydatne informacje kontekstowe.

Inną sytuacją, w której może być potrzebna hierarchia widoków wirtualnych, jest interfejs użytkownika zawierający zestawu funkcji View, które mają ściśle powiązane funkcje, gdzie działanie na jednym wpływa na zawartość jednego lub większej liczby elementów, np. selektora liczb z osobnymi i w dół. W takim przypadku usługi ułatwień dostępu nie mogą uzyskać wystarczających informacji, ponieważ działanie na jednym elemencie sterującym zmienia treść w drugim, a relacja tych ustawień może nie być być widoczny dla usługi.

Aby sobie z tym poradzić, pogrupuj powiązane elementy sterujące z widokiem zawierającym i podaj widok wirtualny hierarchię tego kontenera, aby jasno przedstawić informacje i zachowania dostarczane przez elementów sterujących.

Aby udostępnić hierarchię widoku wirtualnego dla danego widoku, zastąp parametr getAccessibilityNodeProvider() w widoku niestandardowym lub grupie widoków i zwracają implementację AccessibilityNodeProvider Hierarchię widoku wirtualnego możesz wdrożyć, używając biblioteki pomocy z komponentem ViewCompat.getAccessibilityNodeProvider() i zapewnić implementację AccessibilityNodeProviderCompat

Aby uprościć zadanie udostępniania informacji usługom ułatwień dostępu i zarządzania na ułatwieniach dostępu, warto wdrożyć ExploreByTouchHelper Zapewnia on AccessibilityNodeProviderCompat i można go dołączyć jako widok danych AccessibilityDelegateCompat przez połączenie setAccessibilityDelegate. Na przykład zobacz ExploreByTouchHelperActivity Z ExploreByTouchHelper korzystają też widżety platformy, takie jak CalendarView, dzięki swojej widok dziecka SimpleMonthView

Obsługa niestandardowych zdarzeń dotknięcia

Elementy sterujące widokiem niestandardowym mogą wymagać niestandardowego działania zdarzeń dotyku, co pokazuje z poniższych przykładów.

Zdefiniuj działania związane z kliknięciem

Jeśli widżet używa funkcji OnClickListener lub OnLongClickListener system obsługuje ACTION_CLICK oraz ACTION_LONG_CLICK za Ciebie. Jeśli Twoja aplikacja korzysta z bardziej niestandardowego widżetu, który korzysta interfejsu OnTouchListener. definiować niestandardowe moduły obsługi działań związanych z ułatwieniami dostępu związanymi z kliknięciami. W tym celu wywołaj metodę replaceAccessibilityAction() dla każdego działania, jak widać w tym fragmencie kodu:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    // Assumes that the widget is designed to select text when tapped, and selects
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_CLICK,
        getString(R.string.select)
    ) { view, commandArguments ->
        selectText()
    }

    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_LONG_CLICK,
        getString(R.string.select_all)
    ) { view, commandArguments ->
        selectAllText()
    }
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Assumes that the widget is designed to select text when tapped, and select
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_CLICK,
            getString(R.string.select),
            (view, commandArguments) -> selectText());

    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_LONG_CLICK,
            getString(R.string.select_all),
            (view, commandArguments) -> selectAllText());
}

Tworzenie niestandardowych zdarzeń kliknięcia

Niestandardowy element sterujący może używać interfejsu onTouchEvent(MotionEvent) detektor do wykrywania ACTION_DOWN i Wydarzenia: ACTION_UP i wywołać specjalne zdarzenie kliknięcia. Aby zachować zgodność z usługami ułatwień dostępu, kod obsługuje to zdarzenie kliknięcia niestandardowego, musi:

  1. Wygeneruj odpowiedni AccessibilityEvent dla zinterpretowanego działania kliknięcia.
  2. Włącz usługi ułatwień dostępu, aby wykonywać niestandardowe kliknięcia w przypadku użytkowników, którzy nie mogą tego zrobić. użyj ekranu dotykowego.

Aby skutecznie spełnić te wymagania, Twój kod musi zastąpić performClick(), który musi wywoływać superimplementację tej metody i wykonać dowolne wymagane przez zdarzenie kliknięcia. Po wykryciu niestandardowego działania kliknięcia kod ten musi wywołać metodę Metoda performClick(). Następujący przykładowy kod ilustruje ten wzorzec.

Kotlin

class CustomTouchView(context: Context) : View(context) {

    var downTouch = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        super.onTouchEvent(event)

        // Listening for the down and up touch events.
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downTouch = true
                true
            }

            MotionEvent.ACTION_UP -> if (downTouch) {
                downTouch = false
                performClick() // Call this method to handle the response and
                // enable accessibility services to
                // perform this action for a user who can't
                // tap the touchscreen.
                true
            } else {
                false
            }

            else -> false  // Return false for other touch events.
        }
    }

    override fun performClick(): Boolean {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any.
        super.performClick()

        // Handle the action for the custom click here.

        return true
    }
}

Java

class CustomTouchView extends View {

    public CustomTouchView(Context context) {
        super(context);
    }

    boolean downTouch = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        // Listening for the down and up touch events
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downTouch = true;
                return true;

            case MotionEvent.ACTION_UP:
                if (downTouch) {
                    downTouch = false;
                    performClick(); // Call this method to handle the response and
                                    // enable accessibility services to
                                    // perform this action for a user who can't
                                    // tap the touchscreen.
                    return true;
                }
        }
        return false; // Return false for other touch events.
    }

    @Override
    public boolean performClick() {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any.
        super.performClick();

        // Handle the action for the custom click here.

        return true;
    }
}

Poprzedni wzorzec pomaga zagwarantować zgodność niestandardowego zdarzenia kliknięcia z ułatwieniami dostępu za pomocą metody performClick() do generowania zdarzeń ułatwień dostępu oraz udostępnić punkt wejścia dla usług ułatwień dostępu, które będą działać w imieniu użytkownika wykonującego niestandardową zdarzenie kliknięcia.