I am designing an app with accessibility enabled. I have a rightBarButtonItem
on the navigationBar
, several labels in between and a button located at the bottom.
I want to achieve the following behaviour: Every time the current view is loaded, the VoiceOver focus will:
To ensure such order, I coded in the viewController
navigationController?.view.accessibilityElements = [label1, label2, button, navigationItem.rightBarButtonItem]
It did ensure the read order but the focus order failed at the rightBarButtonItem. It couldn't be clicked.
How to solve this problem?
Every time your current view is loaded, use the UIAccessibilityPostNotification method to get your purpose.
There are several types of change notifications but UIAccessibilityScreenChangedNotification may be the one you're interested in.
It notifies that the whole page has changed including nil
or a UIObject
as incoming parameters :
nil
, the first accessible element in the page is focused. UIObject
, focus is shifted to the specified element . This notification comes along with a vocalization including a sound like announcing a new page.
EDIT
I misunderstood your problem that is pretty much complicated than I thought.
If you want to have an impact on the navigation bar items, you should make the native ones inaccessible and create your own custom elements to order and/or add custom actions for instance.
Let's take your example with a label, a button and a navigation bar including a right bar button (I don't take into account a potential back button ).
Follow the steps hereunder in your view controller :
STEP 1 : create your outlets.
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var myButton: UIButton!
@IBOutlet weak var myRightBarItem: UIBarButtonItem!
STEP 2 : hide your navigation bar items so as not to listen to their vocalization.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController!.navigationBar.accessibilityElementsHidden = true
}
STEP 3 : create an accessible element for the right bar button.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let rightButtonView = myRightBarItem.value(forKey: "view") as? UIView
let navigationBarView = rightButtonView?.superview?.superview?.superview
let newElt = UIAccessibilityElement(accessibilityContainer: self.view)
newElt.accessibilityFrameInContainerSpace = navigationBarView!.convert((rightButtonView?.superview!.frame)!,
to:self.view)
newElt.accessibilityLabel = "new navigation right bar button"
newElt.accessibilityTraits = .button
//Order your elements as you wish.
self.view.accessibilityElements = [myLabel,
myButton,
newElt]
}
The last step consists in adding a single action or more to your right bar button according to your application purpose.
Once done, you can customize with this approach and read/focus order to content view first then the navigation items as stated in your question.
This solution may be optimized but it allows to reach your goal.
You can add a function as an UIAccessibility extension to set the focus on any item when you load the screen, then execute your accessibilityElements
extension UIAccessibility {
static func setFocusTo(_ object: Any?) {
if UIAccessibility.isVoiceOverRunning {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
UIAccessibility.post(notification: .layoutChanged, argument: object)
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.