View(不是 ViewGroup)是否可以包含多个 UI 组件,每个组件都需要 Talkback 支持

Can a View (not ViewGroup) contain multiple UI components that each need Talkback support

背景

我一直在努力剥离一个库,该库使用我在现有应用程序中创建的 Talkback 添加辅助功能。最初我的自定义视图都是 ViewGroups,所以我使用 ViewGroups 得到了令人惊讶的一切(使用 D-pad 的可聚焦导航、初始视图焦点和内容描述)

当我将其移动到独立库时,我注意到它不适用于 View。我以为 ViewGroup 是超类,结果发现 View 是超类。所以我一直在努力寻找一些解决方法来解决我的问题。我开始做下面的事情,有一个基于这个方法的问题...

有问题的代码

public class Accessibility {
    public static ViewGroupAccessibility with(ViewGroup viewGroup) {
        return new ViewGroupAccessibility(viewGroup);
    }
    public static ViewAccessibility with(View view){
        return new ViewAccessibility(view);
    }
}

我已经完全实施 ViewGroupAccessibility 并且我打算完全实施 ViewAccessibility 因为它现在是一个存根。到目前为止,下面的代码适用于 TalkBack,我可以用 ViewGroupsViewGroup 相关的事情,看来我可以做 View 相关的事情Views;但是,我想知道是否需要这样做

我所知道的

Accessibility.with(new RelativeLayout(...))  // Returns ViewGroupAccessibility as RelativeLayout is a ViewGroup
//

...将 return 一个可以处理 ViewGroup 相关内容的 ViewGroupAccessibility,可以包含许多不同的 ViewViewGroup。 (实际使用方法见post底部代码,有哪些方法可用ViewGroupAccessibility

Accessibility.with(new Button(...))  // Returns ViewAccessibility as Button is a View
//

...将 return 一个 ViewAccessibility 只能处理单个 View 相关的东西(这是我的假设)。只想一个Button.

我不知道的事

// Hypothetical Usage
Accessibility
    .with(new ClassThatExtendsView_WithMultipleComponentsThatCanHaveAccessibilitySetOnEachComponentIndividually(...));

// Custom View that extends View
public class ClassThatExtendsView_WithMultipleComponentsThatCanHaveAccessibilitySetOnEachComponentIndividually extends View { 
    ... 
}

另一种提问方式是我能保证如果用户调用Accessibility.with(View)给定的视图将始终是单一视图只要?就像一个按钮。或者View可以由多个组件组成


完整代码

您可以在https://codereview.stackexchange.com/questions/134289/easily-add-accessibility-to-your-app-as-an-afterthought-yes-as-an-afterthought处查看代码(原始代码还有一个GitHub link)。我详细介绍了项目的启动方式、我的设计决策和我未来的目标,所有这些都有助于指导代码审查过程。

但是,这里是 用法 的一个片段,我有 ViewGroup

public class ContributionView extends RelativeLayout implements Mappable<Resume.Contribution> {

    // Called from Constructors
    private void init(AttributeSet attrs, int defStyle) {

        root = (ViewGroup) LayoutInflater.from(getContext()).inflate(
                R.layout.internal_contribution_view, this, true);

        ...

        // Declare Navigation Accessibility
        Accessibility.with(root)
                
                // Disable certain views in the ViewGroup from ever gaining focus
                .disableFocusableNavigationOn(
                        R.id.contribution_textview_creator,
                        R.id.contribution_textview_year)

                // For all focusable views in the ViewGroup, set the D-pad Navigation
                .setFocusableNavigationOn(txtProjectName)
                    .down(R.id.contribution_textview_description).complete()
                .setFocusableNavigationOn(txtContributionDescription)
                    .up(R.id.contribution_textview_name)
                    .down(R.id.contribution_textview_link).complete()
                .setFocusableNavigationOn(txtProjectLink)
                    .up(R.id.project_textview_description).complete()

                // Set which view in the ViewGroup will have be first to be focused
                .requestFocusOn(R.id.contribution_textview_name);

        invalidateView();

    }
  
    private void invalidateView() {

        ...

        // Declare Content Description Accessibility
        Accessibility.with(root)

                // Set the content descriptions for each focusable view in the ViewGroup

                // Set the content description for the Contribution Name
                .setAccessibilityTextOn(txtProjectName)
                    .setModifiableContentDescription(getProjectName())
                        .prepend("Contribution occurred on the Project called ")
                        .append(String.format(" by %s in %s",
                                getProjectCreator(),
                                getContributionYear())).complete()

                // Set the content description for the Contribution Description
                .setAccessibilityTextOn(txtContributionDescription)
                    .setModifiableContentDescription(getContributionDescription())
                        .prepend("Description: ").complete()

                // Set the content description for the Contribution URL
                .setAccessibilityTextOn(txtProjectLink)
                    .setModifiableContentDescription(getProjectLink())
                        .prepend("URL is ").complete();

    }

    ...

}

是的,有一种方法可以在视图的各种 areas/components 之间移动可访问性。不过,这需要一些工作。

从这里开始: https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeProvider.html