iosswiftuiviewvoiceoversubviews

How to disable main UI when overlay appears?


I've built a streaming audio app that looks like this:

enter image description here

When the stream is lost, I overlay this screen:

enter image description here

My issue is that with Voiceover ON, all the underlying controls are still active: I can swipe to them all, and adjust their value.

Here is a snippet of my code for when the signal is lost and regained:

@objc func lostStream() {
    DispatchQueue.main.async {
        self.lossOfSignalBlocker.alpha = 0.0
        self.lossOfSignalBlocker.frame = self.view.bounds
        self.view.addSubview(self.lossOfSignalBlocker)
        self.lossOfSignalBlocker.isUserInteractionEnabled = true
        //UIView.animate(withDuration: 0.2) { self.lossOfSignalBlocker.alpha = 1.0 }
        UIView.animate( withDuration: 0.2, animations: { self.lossOfSignalBlocker.alpha = 1.0 } )

        //Announce loss of signal to Voiceover user.
        UIAccessibilityPostNotification(
            UIAccessibilityAnnouncementNotification,
            "Signal Lost" as NSString
        )
    }
}

@objc func regainedStream() {
    DispatchQueue.main.async {
        UIView.animate( withDuration: 0.2, animations: { self.lossOfSignalBlocker.alpha = 0.0 } )
        { _ in
            self.lossOfSignalBlocker.removeFromSuperview()
        }
    }
}

How do I disable the main UI so that only the overlay responds to any Voiceover-related actions?


Solution

  • OK! I've made it work. In addition to setting 'accessibilityElementsHidden' to TRUE, you have to tell the app that the screen has changed by calling 'UIAccessibilityPostNotification' with the 'UIAccessibilityScreenChangedNotification' notification.

    Here's what that code looks like now:

    @objc func lostStream() {
        DispatchQueue.main.async {
    
            self.lossOfSignalBlocker.alpha = 0.0
            self.lossOfSignalBlocker.frame = self.view.bounds
            self.view.addSubview(self.lossOfSignalBlocker)
            self.lossOfSignalBlocker.isUserInteractionEnabled = true
            UIView.animate( withDuration: 0.1, animations: { self.lossOfSignalBlocker.alpha = 1.0 } )
    
            //Disable Voiceover accessibility controls in main view
            self.tableView.accessibilityElementsHidden = true
    
            //Notify app the screen has changed.
            UIAccessibilityPostNotification(
                UIAccessibilityScreenChangedNotification,
                nil
            )
    
            //Announce loss of signal to Voiceover user.
            UIAccessibilityPostNotification(
                UIAccessibilityAnnouncementNotification,
                "Signal Lost. Reconnecting." as NSString
            )
    
        }
    }
    
    @objc func regainedStream() {
        DispatchQueue.main.async {
    
            UIView.animate( withDuration: 0.2, animations: { self.lossOfSignalBlocker.alpha = 0.0 } )
            { _ in
                self.lossOfSignalBlocker.removeFromSuperview()
            }
    
            //Re-enable Voiceover accessibility controls in main view
            self.tableView.accessibilityElementsHidden = false
    
            //Notify app the screen has changed.
            UIAccessibilityPostNotification(
                UIAccessibilityScreenChangedNotification,
                nil
            )
    
            //Announce signal regained to Voiceover user.
            UIAccessibilityPostNotification(
                UIAccessibilityAnnouncementNotification,
                "Reconnected." as NSString
            )
    
        }
    }