Search code examples
iosuikitaccessibilityvoiceoveruiaccessibility

UIViews behind "pass through" UIView isn't VO accessible


I have a case where a transparent UIViewController is presented over a map view. ViewController.view is transparent and it's a "pass-through" view. This means that all of ViewController's touches are passed to the map view that is behind the VC.

"Pass through" behaviour is implemented by

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for subview in subviews {
        if !subview.isHidden && subview.alpha > 0 && subview.isUserInteractionEnabled && subview.point(inside: convert(point, to: subview), with: event) {
            return true
        }
    }
    return false
}

All touches and gestures work perfectly, but I found that VoiceOver doesn't work at all. MapView isn't VO accessible. I can't select any mapView element with VO. I did some research and found that VO uses a private method:

[UIViewAccessibility(SafeCategory) _accessibilityHitTest:withEvent:]

And looks like this method doesn't use the overridden pointInside method. So does anyone know how to fix it in a safe way?


Solution

  • You can make VoiceOver ignore the view by setting view.isAccessibilityElement = NO;.

    Alternately, you can make view conform to UIAccessibilityContainer protocol. If for some reason that doesn’t work, you can set view.accessibilityElements = @[mapView, ...];