TalkBack in TV-Apps unterstützen

TV-Apps haben manchmal Anwendungsfälle, die es Nutzern, die auf TalkBack angewiesen sind, die Verwendung der App erschweren. Um TalkBack für diese Nutzer zu verbessern, lesen Sie die einzelnen Abschnitte dieses Leitfadens und nehmen Sie bei Bedarf Änderungen in Ihre App vor. Wenn Ihre App benutzerdefinierte Ansichten verwendet, sollten Sie auch in der entsprechenden Anleitung nachlesen, wie Sie die Barrierefreiheit durch benutzerdefinierte Ansichten unterstützen.

Verschachtelte Ansichten verarbeiten

Verschachtelte Ansichten können für TalkBack-Nutzer schwer zu navigieren sein. Wenn möglich, sollte TalkBack entweder die übergeordnete oder die untergeordnete Ansicht fokussieren, aber nicht beides.

Wenn eine Ansicht von TalkBack fokussierbar werden soll, setzen Sie die Attribute focusable und focusableInTouchMode auf true. Dieser Schritt ist erforderlich, da einige Fernsehgeräte den Touchmodus starten und beenden können, während TalkBack aktiviert ist.

Um eine Ansicht nicht fokussierbar zu machen, reicht es aus, das Attribut focusable auf false zu setzen. Wenn die Ansicht jedoch verwertbar ist (d. h., die entsprechende AccessibilityNodeInfo hat ACTION_CLICK), kann sie möglicherweise trotzdem fokussierbar sein.

Beschreibungen für Aktionen ändern

Standardmäßig sagt TalkBack „Drücken Sie die Auswahltaste“ an, um eine Ansicht zu erhalten, die Sie bearbeiten können. Bei einigen Aktionen ist der Begriff „Aktivieren“ keine gute Beschreibung. Sie können die Beschreibung ändern, um eine genauere Beschreibung bereitzustellen:

Kotlin

findViewById<View>(R.id.custom_actionable_view).accessibilityDelegate = object : View.AccessibilityDelegate() {
  override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
    super.onInitializeAccessibilityNodeInfo(host, info)
    info.addAction(
      AccessibilityAction(
        AccessibilityAction.ACTION_CLICK.id,
        getString(R.string.custom_label)
      )
    )
  }
}

Java

findViewById(R.id.custom_actionable_view).setAccessibilityDelegate(new AccessibilityDelegate() {
  @Override
  public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
    super.onInitializeAccessibilityNodeInfo(host, info);
    AccessibilityAction action = new AccessibilityAction(
        AccessibilityAction.ACTION_CLICK.getId(), getString(R.string.custom_label));
    info.addAction(action);
  }
});

Unterstützung für Schieberegler hinzufügen

TalkBack auf Fernsehern unterstützt jetzt Schieberegler. Zum Aktivieren des Schiebereglermodus fügen Sie einer Ansicht ACTION_SET_PROGRESS zusammen mit einem RangeInfo-Objekt hinzu.

Der Nutzer wechselt in den Schiebereglermodus, indem er die mittlere Taste der TV-Fernbedienung drückt. In diesem Modus generieren die Pfeiltasten die Bedienungshilfen ACTION_SCROLL_FORWARD und ACTION_SCROLL_BACKWARD.

Im folgenden Beispiel wird ein Lautstärkeregler mit Stufen von 1 bis 10 implementiert:

Kotlin

/**
 *   This example only provides slider functionality for TalkBack users. Additional logic should
 *   be added for other users. Such logic may reuse the increase and decrease methods.
 */
class VolumeSlider(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
  private val min = 1
  private val max = 10
  private var current = 5
  private var textView: TextView? = null

  init {
    isFocusable = true
    isFocusableInTouchMode = true
    val rangeInfo =
      AccessibilityNodeInfo.RangeInfo(
        AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT,
        min.toFloat(),
        max.toFloat(),
        current.toFloat()
      )
    accessibilityDelegate =
      object : AccessibilityDelegate() {
        override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
          super.onInitializeAccessibilityNodeInfo(host, info)
          info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS)
          info.rangeInfo = rangeInfo
        }

        override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
          if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.id) {
            increase()
            return true
          }
          if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD.id) {
            decrease()
            return true
          }
          return super.performAccessibilityAction(host, action, args)
        }
      }
  }

  override fun onFinishInflate() {
    super.onFinishInflate()
    textView = findViewById(R.id.text)
    textView!!.text = context.getString(R.string.level, current)
  }

  private fun increase() {
    update((current + 1).coerceAtMost(max))
  }

  private fun decrease() {
    update((current - 1).coerceAtLeast(min))
  }

  private fun update(newLevel: Int) {
    if (textView == null) {
      return
    }
    val newText = context.getString(R.string.level, newLevel)
    // Update the user interface with the new volume.
    textView!!.text = newText
    // Announce the new volume.
    announceForAccessibility(newText)
    current = newLevel
  }
}

Java

/**
 *   This example only provides slider functionality for TalkBack users. Additional logic should
 *   be added for other users. Such logic can reuse the increase and decrease methods.
 */
public class VolumeSlider extends LinearLayout {
  private final int min = 1;
  private final int max = 10;
  private int current = 5;
  private TextView textView;

  public VolumeSlider(Context context, AttributeSet attrs) {
    super(context, attrs);
    setFocusable(true);
    setFocusableInTouchMode(true);
    RangeInfo rangeInfo = new RangeInfo(RangeInfo.RANGE_TYPE_INT, min, max, current);
    setAccessibilityDelegate(
        new AccessibilityDelegate() {
          @Override
          public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
            super.onInitializeAccessibilityNodeInfo(host, info);
            info.addAction(AccessibilityAction.ACTION_SET_PROGRESS);
            info.setRangeInfo(rangeInfo);
          }

          @Override
          public boolean performAccessibilityAction(View host, int action, Bundle args) {
            if (action == AccessibilityAction.ACTION_SCROLL_FORWARD.getId()) {
              increase();
              return true;
            }
            if (action == AccessibilityAction.ACTION_SCROLL_BACKWARD.getId()) {
              decrease();
              return true;
            }
            return super.performAccessibilityAction(host, action, args);
          }
        });
  }

  @Override
  protected void onFinishInflate() {
    super.onFinishInflate();
    textView = findViewById(R.id.text);
    textView.setText(getContext().getString(R.string.level, current));
  }

  private void increase() {
    update(Math.min(current + 1, max));
  }

  private void decrease() {
    update(Math.max(current - 1, min));
  }

  private void update(int newLevel) {
    if (textView == null) {
      return;
    }
    String newText = getContext().getString(R.string.level, newLevel);
    // Update the user interface with the new volume.
    textView.setText(newText);
    // Announce the new volume.
    announceForAccessibility(newText);
    current = newLevel;
  }
}