android 如何在ConstraintLayout中创建可访问的焦点组?

ztmd8pv5  于 2023-04-04  发布在  Android
关注(0)|答案(7)|浏览(164)

假设你有一个LinearLayout在一个RelativeLayout中,它包含3个TextViewsartist, song and album

<RelativeLayout
    ...
    <LinearLayout
        android:id="@id/text_view_container"
        android:layout_width="warp_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@id/artist"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Artist"/>

        <TextView
            android:id="@id/song"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Song"/>

        <TextView
            android:id="@id/album"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="album"/>
    </LinearLayout>

    <TextView
        android:id="@id/unrelated_textview1/>
    <TextView
        android:id="@id/unrelated_textview2/>
    ...
</RelativeLayout>

当您激活TalkbackReader并点击LinearLayout中的TextView时,TalkbackReader将读取例如“艺术家”,“歌曲”或“专辑”。
但是你可以把前3个TextViews放入一个焦点小组,方法是:

<LinearLayout
    android:focusable="true
    ...

现在TalkbackReader会读到“艺术家歌曲专辑”。

**2 unrelated TextViews仍然是独立的,不读取,这是我想要实现的行为。

(See Google codelabs示例供参考)
我现在试图用ConstrainLayout重新创建这种行为,但看不出如何。

<ConstraintLayout>
    <TextView artist/>
    <TextView song/>
    <TextView album/>
    <TextView unrelated_textview1/>
    <TextView unrelated_textview2/>
</ConstraintLayout>

将小部件放入“组”似乎不起作用:

<android.support.constraint.Group
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:importantForAccessibility="yes"
    app:constraint_referenced_ids="artist,song,album"
    />

那么,我如何在ConstrainLayout中重新创建可访问性焦点组?

**[编辑]:**似乎是这样的,创建解决方案的唯一方法是在外部ConstraintLayout上使用“focusable=true”和/或在视图本身上使用“focusable=false”。这有一些缺点,在处理键盘导航/切换框时应该考虑:

https://github.com/googlecodelabs/android-accessibility/issues/4

icnyk63a

icnyk63a1#

基于ViewGroups的焦点组仍然可以在ConstraintLayout中工作,所以你可以用ConstraintLayouts替换LinearLayoutsRelativeLayouts,TalkBack仍然可以按预期工作。但是,如果你试图避免在ConstraintLayout中 * 嵌套 * ViewGroups,保持平面视图层次结构的设计目标,这里有一种方法可以做到这一点。
TextViews从您提到的焦点ViewGroup直接移动到顶级ConstraintLayout。现在我们将使用ConstraintLayout约束在这些TextViews之上放置一个简单的透明View。每个TextView将成为顶级ConstraintLayout的成员,因此布局将是平坦的。由于覆盖层位于TextViews的顶部,因此它将在底层TextViews之前接收所有触摸事件。以下是布局结构:

<ConstaintLayout>
    <TextView>
    <TextView>
    <TextView>
    <View> [overlays the above TextViews]
</ConstraintLayout>

我们现在可以手动为覆盖层指定一个内容描述,它是每个底层TextViews的文本的组合。为了防止每个TextView接受焦点并说出自己的文本,我们将设置android:importantForAccessibility="no"。当我们触摸覆盖视图时,我们听到TextViews的组合文本。
以上是一般的解决方案,但更好的是,将是一个自定义覆盖视图的实现,将自动管理事情。下面显示的自定义覆盖遵循ConstraintLayoutGroup助手的一般语法,并自动化上面概述的大部分处理。
自定义覆盖执行以下操作:
1.接受一个id列表,这些id将按控件分组,如ConstraintLayoutGroup助手。
1.通过在每个视图上设置View.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO)来禁用分组控件的可访问性。(这避免了手动执行此操作。)
1.单击自定义控件时,它会将分组视图的文本串联到辅助功能框架。为视图收集的文本来自contentDescriptiongetText()hint。(这避免了手动执行此操作。另一个优点是,它还将在应用运行时拾取对文本所做的任何更改。)

  • 覆盖视图仍需要在布局XML中手动定位,以覆盖TextViews。*

下面是一个示例布局,显示了问题中提到的ViewGroup方法和自定义覆盖。右边是使用自定义控件的覆盖方法。顶部标记为“初始焦点”的TextView只是为了捕获初始焦点,以便于比较两种方法。
选择ConstraintLayout后,TalkBack会显示“艺术家、歌曲、专辑”。

选择自定义视图覆盖后,TalkBack还会显示“艺术家、歌曲、专辑”。

下面是自定义视图的示例布局和代码。* 注意:虽然这个自定义视图使用TextViews可以达到指定的目的,但它并不是传统方法的可靠替代品。例如:自定义覆盖将说出扩展TextView(如EditText)的视图类型的文本,而传统方法则不会。
在GitHub上查看sample project

活动_主要.xml

<android.support.constraint.ConstraintLayout 
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/viewGroup"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:gravity="center_horizontal"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/viewGroupHeading">

        <TextView
            android:id="@+id/artistText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Artist"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/songText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="Song"
            app:layout_constraintStart_toStartOf="@+id/artistText"
            app:layout_constraintTop_toBottomOf="@+id/artistText" />

        <TextView
            android:id="@+id/albumText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="Album"
            app:layout_constraintStart_toStartOf="@+id/songText"
            app:layout_constraintTop_toBottomOf="@+id/songText" />

    </android.support.constraint.ConstraintLayout>

    <TextView
        android:id="@+id/artistText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Artist"
        app:layout_constraintBottom_toTopOf="@+id/songText2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="@+id/viewGroup" />

    <TextView
        android:id="@+id/songText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Song"
        app:layout_constraintStart_toStartOf="@id/artistText2"
        app:layout_constraintTop_toBottomOf="@+id/artistText2" />

    <TextView
        android:id="@+id/albumText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Album"
        app:layout_constraintStart_toStartOf="@+id/artistText2"
        app:layout_constraintTop_toBottomOf="@+id/songText2" />

    <com.example.constraintlayoutaccessibility.AccessibilityOverlay
        android:id="@+id/overlay"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:focusable="true"
        app:accessible_group="artistText2, songText2, albumText2, editText2, button2"
        app:layout_constraintBottom_toBottomOf="@+id/albumText2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/guideline"
        app:layout_constraintTop_toTopOf="@id/viewGroup" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

    <TextView
        android:id="@+id/viewGroupHeading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:importantForAccessibility="no"
        android:text="ViewGroup"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textStyle="bold"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView4" />

    <TextView
        android:id="@+id/overlayHeading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:importantForAccessibility="no"
        android:text="Overlay"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="@+id/viewGroupHeading" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="Initial focus"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

AccessibilityOverlay.java

public class AccessibilityOverlay extends View {
    private int[] mAccessibleIds;

    public AccessibilityOverlay(Context context) {
        super(context);
        init(context, null, 0, 0);
    }

    public AccessibilityOverlay(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0, 0);
    }

    public AccessibilityOverlay(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public AccessibilityOverlay(Context context, @Nullable AttributeSet attrs,
                                int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr, defStyleRes);
    }

    private void init(Context context, @Nullable AttributeSet attrs,
                      int defStyleAttr, int defStyleRes) {
        String accessibleIdString;

        TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.AccessibilityOverlay,
            defStyleAttr, defStyleRes);

        try {
            accessibleIdString = a.getString(R.styleable.AccessibilityOverlay_accessible_group);
        } finally {
            a.recycle();
        }
        mAccessibleIds = extractAccessibleIds(context, accessibleIdString);
    }

    @NonNull
    private int[] extractAccessibleIds(@NonNull Context context, @Nullable String idNameString) {
        if (TextUtils.isEmpty(idNameString)) {
            return new int[]{};
        }
        String[] idNames = idNameString.split(ID_DELIM);
        int[] resIds = new int[idNames.length];
        Resources resources = context.getResources();
        String packageName = context.getPackageName();
        int idCount = 0;
        for (String idName : idNames) {
            idName = idName.trim();
            if (idName.length() > 0) {
                int resId = resources.getIdentifier(idName, ID_DEFTYPE, packageName);
                if (resId != 0) {
                    resIds[idCount++] = resId;
                }
            }
        }
        return resIds;
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();

        View view;
        ViewGroup parent = (ViewGroup) getParent();
        for (int id : mAccessibleIds) {
            if (id == 0) {
                break;
            }
            view = parent.findViewById(id);
            if (view != null) {
                view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
            }
        }
    }

    @Override
    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
        super.onPopulateAccessibilityEvent(event);

        int eventType = event.getEventType();
        if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED ||
            eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED &&
                getContentDescription() == null) {
            event.getText().add(getAccessibilityText());
        }
    }

    @NonNull
    private String getAccessibilityText() {
        ViewGroup parent = (ViewGroup) getParent();
        View view;
        StringBuilder sb = new StringBuilder();

        for (int id : mAccessibleIds) {
            if (id == 0) {
                break;
            }
            view = parent.findViewById(id);
            if (view != null && view.getVisibility() == View.VISIBLE) {
                CharSequence description = view.getContentDescription();

                // This misbehaves if the view is an EditText or Button or otherwise derived
                // from TextView by voicing the content when the ViewGroup approach remains
                // silent.
                if (TextUtils.isEmpty(description) && view instanceof TextView) {
                    TextView tv = (TextView) view;
                    description = tv.getText();
                    if (TextUtils.isEmpty(description)) {
                        description = tv.getHint();
                    }
                }
                if (description != null) {
                    sb.append(",");
                    sb.append(description);
                }
            }
        }
        return (sb.length() > 0) ? sb.deleteCharAt(0).toString() : "";
    }

    private static final String ID_DELIM = ",";
    private static final String ID_DEFTYPE = "id";
}

属性.xml

定义自定义覆盖视图的自定义属性。

<resources>  
    <declare-styleable name="AccessibilityOverlay">  
        <attr name="accessible_group" format="string" />  
    </declare-styleable>  
</resources>
u59ebvdq

u59ebvdq2#

我最近遇到了同样的问题,我决定使用新的ConstraintLayout帮助器(自constraintlayout 1.1起可用)实现一个新的Class,以便我们可以以使用Group视图的相同方式使用它。
该实现是Cheticamp's answer的简化版本,他的想法是创建一个新的视图来处理可访问性。
下面是我的实现:

package com.julienarzul.android.accessibility

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.view.accessibility.AccessibilityEvent
import androidx.constraintlayout.widget.ConstraintHelper
import androidx.constraintlayout.widget.ConstraintLayout

class ConstraintLayoutAccessibilityHelper
@JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {

    init {
        importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            isScreenReaderFocusable = true
        } else {
            isFocusable = true
        }
    }

    override fun updatePreLayout(container: ConstraintLayout) {
        super.updatePreLayout(container)

        if (this.mReferenceIds != null) {
            this.setIds(this.mReferenceIds)
        }

        mIds.forEach {
            container.getViewById(it)?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
        }
    }

    override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) {
        super.onPopulateAccessibilityEvent(event)

        val constraintLayoutParent = parent as? ConstraintLayout
        if (constraintLayoutParent != null) {
            event.text.clear()

            mIds.forEach { id ->
                val view: View? = constraintLayoutParent.getViewById(id)
                // Adds this View to the Accessibility Event only if it is currently visible
                if (view?.isVisible == true) {
                    view.onPopulateAccessibilityEvent(event)
                }
            }
        }
    }
}

也可作为要点:https://gist.github.com/JulienArzul/8068d43af3523d75b72e9d1edbfb4298
您可以像使用组一样使用它:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/myTextView"
        />

    <ImageView
        android:id="@+id/myImageView"
        />

    <com.julienarzul.android.accessibility.ConstraintLayoutAccessibilityHelper
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:constraint_referenced_ids="myTextView,myImageView" />

</androidx.constraintlayout.widget.ConstraintLayout>

此示例将TextView和ImageView组织在一个组中,以实现辅助功能。您仍然可以添加其他视图,这些视图将获得焦点并由ConstraintLayout中的辅助功能读取器读取。
视图是透明的,但您可以使用常规约束布局属性选择聚焦时显示视图的区域。
在我的示例中,辅助功能组显示在整个ConstraintLayout上,但您可以通过修改app:"layout_constraint..."属性来选择将其与某些或所有引用的视图对齐。

编辑:根据@Mel'在评论中的建议,我更新了ConstraintLayoutAccessibilityHelper类,以确保在Accessibility事件中只添加可见的视图。

hrysbysz

hrysbysz3#

设置内容描述

确保ConstraintLayout被设置为可聚焦,并带有显式的内容描述。此外,确保子TextViews设置为可聚焦,除非您希望它们被独立读取。

可扩展标记语言

<ConstraintLayout
  android:focusable="true"
  android:contentDescription="artist, song, album">

    <TextView artist/>
    <TextView song/>
    <TextView album/>
    <TextView unrelated 1/>
    <TextView unrelated 2/>

</ConstraintLayout>

** java **

如果您希望在代码中动态设置ConstraintLayout的内容描述,则可以将每个相关TextView的文本值连接起来:

String description = tvArtist.getText().toString() + ", " 
    + tvSong.getText().toString() + ", "
    + tvAlbum.getText().toString();

constraintLayout.setContentDescription(description);

辅助功能结果

启用Talkback后,ConstraintLayout现在将获得焦点并读出其内容描述。
屏幕截图,Talkback显示为标题:

详解

下面是上面示例截图的完整XML。注意,focusable和content description属性只在父级ConstraintLayout中设置,而不是在子级TextView中设置。这使得TalkBack永远不会关注单个子视图,而只关注父级容器(因此,只阅读父级容器的内容描述)。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:contentDescription="artist, song, album"
    android:focusable="true"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text1"
        style="@style/TextAppearance.AppCompat.Display1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Artist"
        app:layout_constraintBottom_toTopOf="@+id/text2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/text2"
        style="@style/TextAppearance.AppCompat.Display1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Song"
        app:layout_constraintBottom_toTopOf="@+id/text3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text1" />

    <TextView
        android:id="@+id/text3"
        style="@style/TextAppearance.AppCompat.Display1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Album"
        app:layout_constraintBottom_toTopOf="@id/text4"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text2" />

    <TextView
        android:id="@+id/text4"
        style="@style/TextAppearance.AppCompat.Display1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Unrelated 1"
        app:layout_constraintBottom_toTopOf="@id/text5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text3" />

    <TextView
        android:id="@+id/text5"
        style="@style/TextAppearance.AppCompat.Display1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Unrelated 2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text4" />
</android.support.constraint.ConstraintLayout>

嵌套焦点项

如果您希望不相关的TextViews能够独立于父级ConstraintLayout进行聚焦,则可以将这些TextViews也设置为focusable=true。这将导致这些TextViews变得可聚焦并单独读取,* 在 * ConstraintLayout之后。
如果要将不相关的TextViews分组到单个TalkBack公告中(与ConstraintLayout分开),则选项有限:
1.将不相关的视图嵌套到另一个ViewGroup中,并使用它自己的内容描述,或者
1.只在第一个不相关的项目上设置focusable=true,并将其内容描述设置为该子组的单个公告(例如“不相关的项目”)。
选项#2会被认为是一种技巧,但它允许您维护一个平面视图层次结构(如果您真的想避免嵌套)。
但是如果你要实现焦点项的多个子分组,更合适的方法是将分组组织为嵌套的ViewGroups。根据Android关于自然分组的可访问性文档:
要为一组相关内容定义适当的聚焦模式,请将结构的每一部分放入其自己的可聚焦ViewGroup中

wko9yo5t

wko9yo5t4#

Android引入了android:screenReaderFocusable来对约束布局中的内容进行分组。这将适用于上述情况。但需要API级别27。
https://developer.android.com/guide/topics/ui/accessibility/principles#content-groups

juud5qan

juud5qan5#

1.将约束布局设置为focusable(通过在约束布局中设置android:focusable=“true”)
1.将内容描述设置为约束布局

  1. set focusable=“false”用于不包含的视图。

基于注解编辑仅适用于约束布局中存在单个焦点组的情况。

x33g5p2x

x33g5p2x6#

仅在XML中。
对于我的特殊情况,我默认情况下将视图分组在可访问性中,并将“important for accessibility field”设置为yes。android: importantForAccessibility="yes"这没有任何作用,
但当我转到EACH视图并分别设置importantForAccessibility时
android: importantForAccessibility="yes"如果你想宣布
android: importantForAccessibility="no",如果你不想让它被公布--这解决了我的问题。

2fjabf4q

2fjabf4q7#

我已经做了Julien Arzul的答案的一个版本,它不需要你手动为不可见的View设置约束。这个类扩展了ConstraintLayout的Layer类,它会自动适应显示在引用的View id上。

import android.content.Context
    import android.util.AttributeSet
    import android.view.View
    import android.view.accessibility.AccessibilityEvent
    import androidx.constraintlayout.helper.widget.Layer
    import androidx.constraintlayout.widget.ConstraintLayout
    import androidx.core.view.isVisible
    
    /**
     * This class can be used inside ConstraintLayouts to aggregate a particular group of its children into a single accessibility
     * focus group so they are all read together, in the same swipe stop.
     * This creates an invisible view that is drawn above all the specified children and receives focus in their place, reading all
     * of their descriptions in sequence.
     * The children's ids should be specified just like in a ConstraintLayout's Group, with app:constraint_referenced_ids.
     */
    
    class ConstraintLayoutFocusGroup @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : Layer(context, attrs, defStyleAttr) {
    
        init {
            importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
            isScreenReaderFocusable = true
        }
    
        override fun updatePreLayout(container: ConstraintLayout) {
            super.updatePreLayout(container)
    
            if (this.mReferenceIds != null) {
                this.setIds(this.mReferenceIds)
            }
    
            val children = mIds.map { container.getViewById(it) }
            makeNotImportantForAccessibility(children)
        }
    
        override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) {
            super.onPopulateAccessibilityEvent(event)
    
            val constraintLayoutParent = parent as? ConstraintLayout
            if (constraintLayoutParent != null) {
                event.text.clear()
    
                val children = mIds.map { constraintLayoutParent.getViewById(it) }
                populateWithChildrenInfo(event, children)
            }
        }
    
        private fun makeNotImportantForAccessibility(views: Iterable<View?>) {
            views.filterNotNull().forEach { child ->
                child.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
            }
        }
    
        private fun populateWithChildrenInfo(event: AccessibilityEvent, views: Iterable<View?>) {
            views.filterNotNull().forEach { view ->
                if (view.isVisible) {
                    view.onPopulateAccessibilityEvent(event)
                }
            }
        }
    }

有一个问题,我最近一直在面对它,虽然(这也发生在朱利安的版本),如果你有一个解决方案,请让我知道。
Since version 13 Talkback has a feature that recognizes text/icons/images without content descriptions and does OCR on them说出它在视图中识别的内容,因此使用此解决方案,Talkback首先像我们想要的那样读取我们不可见的视图的描述,但之后它还读取我们试图通过importantForAccessibility=“no”隐藏的视图的内容。
所以它最后会说:“textViewOneTexttextViewTwoText;检测到:text textViewOneText**textViewTwoText"。

相关问题