有時,電視應用程式的使用案例會讓依賴 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);
}
});
新增滑桿支援功能
TV 版 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;
}
}