תמיכה ב-TalkBack באפליקציות לטלוויזיה

לפעמים יש תרחישי שימוש באפליקציות לטלוויזיה שמקשים על משתמשים שמסתמכים על TalkBack להשתמש באפליקציה. כדי לספק חוויית TalkBack טובה יותר למשתמשים האלה, כדאי לעיין בכל אחד מהקטעים במדריך הזה ולבצע שינויים באפליקציה לפי הצורך. אם האפליקציה משתמשת בתצוגות מותאמות אישית, כדאי לעיין גם במדריך המתאים שמתאר איך לתמוך בנגישות באמצעות תצוגות מותאמות אישית.

איך מטפלים בתצוגות מוטמעות

למשתמשי TalkBack קשה לנווט בתצוגות מקוננות. בכל מקום שאפשר, כדאי להגדיר ש-TalkBack יוכל להתמקד בתצוגה של ההורה או בתצוגה לילדים, אבל לא בשתיהן.

כדי להגדיר תצוגה שניתן להתמקד בה באמצעות TalkBack, צריך להגדיר את המאפיין focusable ואת המאפיין focusableInTouchMode לערך true. השלב הזה נחוץ כי יכול להיות שמכשירי טלוויזיה מסוימים ייכנסו למצב מגע ויצאו ממנו בזמן ש-TalkBack פעיל.

כדי להגדיר תצוגה כלא ניתנת למיקוד, מספיק להגדיר את המאפיין focusable לערך false. עם זאת, אם התצוגה המפורטת ניתנת לפעולה (כלומר, למדיניות AccessibilityNodeInfo התואמת שלה יש ACTION_CLICK), עדיין אפשר להתמקד בה.

שינוי התיאורים של הפעולות

כברירת מחדל, TalkBack מכריז על תצוגות שאפשר לבצע בהן פעולות: "כדי להפעיל, צריך ללחוץ על 'בחירה'". במקרים מסוימים, המילה 'הפעלה' לא מתארת היטב את הפעולה. כדי לספק תיאור מדויק יותר, אפשר לשנות אותו:

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);
  }
});

הוספת תמיכה במחוונים

ל-TalkBack בטלוויזיה יש תמיכה מיוחדת במכווני עוצמה. כדי להפעיל את מצב פס ההזזה, מוסיפים את ACTION_SET_PROGRESS לתצוגה יחד עם אובייקט RangeInfo.

המשתמש עובר למצב פס גלילה בלחיצה על הלחצן המרכזי בשלט הרחוק של הטלוויזיה. במצב הזה, לחצני החיצים יוצרים פעולות נגישות של ACTION_SCROLL_FORWARD ושל ACTION_SCROLL_BACKWARD.

בדוגמה הבאה מוטמע פס הזזה של עוצמת הקול עם רמות מ-1 עד 10:

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;
  }
}