iOS:How to code accessibility, that if user tap on the parent view then whole view should speak, if user tap the child view so only it should be speak

0

I am adding a demo code here of my problem. For this I have created a parent view in which I have 2 child views, I have added "accessibilityElement(children: .combine)" code to the parent view, which combines all the elements while I tap on the view. but I want if the user tap on the parent view then the voiceover should speak all views but if the user taps on a button, then it should separately speak the button.

Requirement: If the user taps on the parent view then it should speak all the elements of the view but if the user taps on the button then it should only speak the button, not the full view again.

Demo Video link: https://drive.google.com/file/d/1aOuDoTiDizQstfEHiTy-8OoGqXcD_uk0/view?usp=sharing

In this video, I want if the user taps on the button it should speak only button, not the full view again.

The sample code:

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            topView
            Button("Show details") {              
                print("Tapped show detail")
            }.accessibilityElement()
            .accessibilityLabel(Text("This is show detail"))       // I want if user tap on this button separatly then it should only speak the button lable only, not the full content again.
            bottomView
        }.accessibilityElement(children: .combine)     // By this code it will read the topView, button, and bottomView
        .padding()
    }
    
    @ViewBuilder
    private var topView: some View {
        VStack(alignment: .leading, spacing: 5) {
            Text("First Text")
            Text("Second Text")
        }
    }
    
    @ViewBuilder
    private var bottomView: some View {
        VStack(alignment: .leading, spacing: 5) {
            Text("Third Text")
            Text("Fourth Text")
        }
    }
}

Requirement: If the user taps on the parent view then it should speak all the elements but if the user taps on the button then it should only speak the button, not the full view again.

Replies

When you use accessibilityElement(children: .combine), and there is a Button in the children, then the new combined group will inherit the isButton trait (in other words, the group becomes a Button). The VoiceOver system automatically converts the action to the default activate accessibility action and the Button's label is no longer announced (however, you explicitly set an accessibilityLabel on the Button which is what is used). That's why you see this behavior; I do not know if this is a bug, just what I have observed.

You have also redeclared Button as an accessible element which removes its previous label "Show details", and it instead is using the "This is show detail" label that you told it to use for accessibility.

Wrt Voiceover dropping the Button's label unless an accessibilityLabel is explicitly applied; my theory is that VoiceOver assumes the Button's siblings accessibilityLabels will provide the context necessary to activate the Button group. However, as you can imagine this could lead to unexpected consequences.

I don't think it's possible to achieve your requirement because by using combine, the group becomes the leaf in the accessibility tree which encompasses the Button, thus the Button cannot also be a leaf. If you try using contain, then each element will be a leaf and therefore not in a group and the button will remain tappable on its own.