VoiceOver parent and child views as accessibility elements
Asked Answered
R

4

14

I have a simple UIView hierarchy. There is a parent view A which contains view B and C. If I set all views as accessibility element, only view A is accessible. Views B and C are not clickable. I need all views (A, B and C) to be accessibility elements.

I know you can achieve that by putting all views (A, B and C) at the same level, but view hierarchy in my app does not allow any changes.

Do you have any solution for that?

Rissole answered 9/8, 2016 at 11:24 Comment(1)
Have you looked into the UIAccessibilityContainer protocol?Marlow
A
7

Is view A an accessibility element? For subviews to be accessible, the containing view must not be an accessibility element.

view.isAccessibilityElement = false

If you need the third view, A, to be accessible, then make it a sibling view of B and C.

Adorn answered 10/8, 2016 at 14:30 Comment(1)
I couldn't make A sibling of B and C, as this was already the view hierarchy in my app, but I used parent view of A and UIAccessibilityContainer protocol to resolve my problem. Details of the solution you can find below in the answer.Rissole
O
7

1) Make all your views i.e A, B, C as accessibilityElement.

   A.isAccessibilityElement = true
   B.isAccessibilityElement = true
   C.isAccessibilityElement = true

2) If your parent view is parentView, then set all these views as its AccessibilityElements

parentView.accessibilityElements = [A, B, C]

PS :- accessibilityElements creates a group of all elements mentioned in array. This is also used to change the order of elements. But the only thing you have to keep in mind is to mention all the elements you have in parentView to this array otherwise the element will get skip while swiping on views.

Oxpecker answered 12/3, 2019 at 6:13 Comment(1)
Doesn't work for me.Christiansand
R
5

Finally I resolved it using UIAccessibilityContainer protocol and using my existing view hierarchy: A (parent), B (child) and C (child). I used another view, say X which was parent of A and implemented a UIAccessibilityContainer protocol in it. Here is example code of creation an array of UIAccessibilityElements which was created in view X.

- (NSArray *)voiceOverElements {
    if (!_voiceOverElements) {
        UIAccessibilityElement *element = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
        CGRect frame = UIAccessibilityConvertFrameToScreenCoordinates(A.frame, self);
        element.accessibilityFrame = frame;
        _voiceOverElements = @[element];
        for (UIView *view in A.subviews) {
            UIAccessibilityElement * element = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
            CGRect frame = UIAccessibilityConvertFrameToScreenCoordinates(view.frame, A);
            element.accessibilityFrame = frame;
            _voiceOverElements = [_voiceOverElements arrayByAddingObject:element];
        }
    }
    return _voiceOverElements;
}

In the same view (X), UIAccessibilityContainer protocol was implemented as follows:

- (BOOL)isAccessibilityElement {
    return NO;
}

- (id)accessibilityElementAtIndex:(NSInteger)index {
    return [self.voiceOverElements objectAtIndex:index];
}

- (NSInteger)accessibilityElementCount {
    return self.voiceOverElements.count;
}

- (NSInteger)indexOfAccessibilityElement:(id)element {
    return [self.voiceOverElements indexOfObject:element];
}
Rissole answered 11/8, 2016 at 8:47 Comment(0)
I
0

Here is working version

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let A = UIView(frame: CGRect(x: 50, y: 100, width: 300, height: 300))
        A.backgroundColor = .blue
        A.accessibilityLabel = "Parent View"

        let B = UIView(frame: CGRect(x: 50, y: 100, width: 50, height: 50))
        B.backgroundColor = .red
        B.accessibilityLabel = "Child View 1"

        let C = UIView(frame: CGRect(x: 150, y: 150, width: 50, height: 50))
        C.backgroundColor = .green
        C.accessibilityLabel = "Child View 2"

        A.addSubview(B)
        A.addSubview(C)

        A.isAccessibilityElement = true

        B.isAccessibilityElement = true

        C.isAccessibilityElement = true

        view.addSubview(A)

//        view.accessibilityElements = [A, B, C] // Won't work here, i dunno why

        view.accessibilityElements = [B, C, A]
    }
}
Ivelisseivens answered 12/3, 2024 at 20:34 Comment(1)
Please, share where was an issueMotionless

© 2022 - 2025 — McMap. All rights reserved.