Accessible custom modals in SwiftUI - swift

I'm trying to make a custom modal view in SwiftUI be more accessible with VoiceOver.
I've set .accessibility(addTraits: .isModal) but VoiceOver till focus elements under the modal. So then I tried to set .accessibility(hidden: true) when the modal is visible. That kind of works, but VoiceOver focus the element closest to the position of the button that opened the modal, but it would be more logical to focus the first element in the modal.
Not sure how to solve this and what the best way forward is.
Gist with code for popup.
https://gist.github.com/tfsjohan/80e9e39287f65fc044222468b834d74b

What it worked for me was to set .accessibilityElement(children: .ignore) to the sibling views and sending UIAccessibility.post(notification: .screenChanged, argument: nil) before presenting the popup.
In that way, the components behind the popup aren't available anymore during the navigation, and the screen change event moved the focus of the voice over to the element with the highest priority.

Related

How to make a popover non-modal?

I am trying to have popovers over console.log(), helloword(), and others. However, since popovers in MUI are modal, I cannot show other popovers unless I click outside the popover that is currently opened.
Is there a way to disable modal behavior?
So far, I forced non-modality via properties:
style ={{width:0, height:0}}
modal={null}
hideBackdrop={true}
disableBackdropClick={true}
disableAutoFocus={true}
disableEnforceFocus={true}
What about a modal={true|false}?

TVOS requires 2 Menu Button Presses to exit to Dashboard from Root Controller

I have been charged with updating an existing TVOS project. I have run into a bit of a snag.
If I am on the root controller(ie: the controller that presents on app launch.)
Pressing the Menu button takes me to an empty gray/white screen. A second press of menu returns me to the Dashboard.
I have tried to use the hierarchy viewer to see what exactly that gray/white screen is, but it has not helped. The gray/white screen consists of a UIWindow with a UILayoutContainerView, that contains a single UINavigationTransitionView in it. I can find no other identifiable characteristics about it to help me identify what exactly is going on.
When launched the app loads a UINavigationController that presents a UIViewController. Neither the Nav controller nor the presented ViewController override pressesBegin, pressesEnd or assign any gestureRecongnizers to intercept or otherwise override the Menu button functionality.
Near as I can tell the app should exhibit the default Menu button pressed behavior of navigate back to the root, then exit to the Dashboard once at the root. That said, the Menu button does navigate backwards as it should. It just does not terminate the app once at the root. When it does go to the gray/white screen none of the functions: applicationWill... are executed until after the second press of the Menu button on the remote. The app will also resume to this gray/white screen instead.
My question is thus, what is going on here. Baring that how can I
debug this behavior more effectively.
I have tried to be thorough with this explanation. I recognize that without code things get hard. Thing is, I have no idea what code would be relevant so any guidance or requests for specific code that may be useful will be posted.
Thanks.
Let's call your navigation controller A and the presented view controller B.
It sounds like what's happening is that A doesn't actually have any children, or it has a blank view controller as it's only child. I'm assuming that you never call pushViewController(_, animated:) on A? What are you passing to A when you create it with init(rootViewController:)?
When you press the Menu button the first time, UIKit is automatically dismissing the presented view controller B, and revealing the empty navigation controller A. The gray screen you see is actually the tvOS wallpaper, which is rendered outside the app's view hierarchy.
Then pressing the Menu button the second time actually causes the app to resign, since the navigation controller A doesn't have any more children to pop.
So it sounds like you should either:
Add the view controller B as a child of A, instead of presenting it.
Or, set B as the root view controller and forget about A.

Modal View Issue

I have an issue with some of my views, here is a breif outline of my setup:
Tab Bar Controller
|
--View Controller 1
|
--View Controller 2
|
--View Controller 2
On a certain action, View Controller 1 will display a modal dialogue. Within this dialogue, if the user performs another action, then another modal dialogue is shown, using the first modal dialogue to present the view.
On the 2nd ModalDialog I have a UITextField, however when I attempt to type into the text field, nothing happens. Even though the keyboard is displayed and the textFieldDidBeginEditing method is called. I have setup the UITextFieldDelegate and the nessessary responders, but to no avail.
Does anyone know what would cause this issue?
Many Thanks
I've found that on a number of occasions with changing views and with popovers that text fields haven't focused correctly with symptoms like you describe. On these occasions I end up deferring the becomeFirstResponder call until the animation has finished or the view has loaded - for example in a view controllers viewDidAppear method.
Or, simply delay the call to becomeFirstResponder with an appropriate guestimate of the time it will take for the views to change / animate / etc. ie:
[textField performSelector:#selector(becomeFirstResponder)
withObject:nil
afterDelay:0.3];
I would try to 'chain' the modal dialogs from the view controller if that's possible.
The VC opens the 1st modal dialog
Your 1st modal dialog notifies the VC (using delegation probably).
(Maybe required) Close the 1st modal dialog
The VC opens the 2nd modal dialog
Happiness!
I'm not sure what you mean with "modal dialogue" -- I assume you mean either a modally presented view controller with a UIModalPresentationFormSheet modal presentation style or a UIPopoverController.
Here's my best guess: I'm pretty sure that your "modal dialogue" captures all user interactions (by default). So when pushing the first one, it captures all input focus. When pushing the second one, it's capture conflicts with the previous one and hence the keyboard will not work.
Anyways, both types of "modal dialogues" are not meant to be stacked. Even if it may work technically, I dislike like it form a interaction-design perspective. Instead of trying to fix the bug or work around it, try to rethink you modal dialogue. You may fit everything into a single one. For example by using a navigation controller inside that view, or by replacing the the view or by flipping it's contents... etc.
Hope this helps, Max
If I were you I would consider revising the navigational hierarchy. Modal dialogs are considered bad enough as it is, but incorporating a modal dialog within a modal dialog is user interface suicide. It causes confusion to the user and is very non-traditional. Is there any way you can use the first modal popup and simply exchange the content?
A side note: You mentioned setting up the view as being a UITextViewDelegate. Did you the view as the delegate for the textbox? Are you returning NO or FALSE from - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string?

Does this popup view violate HIGS?

Will using a popup view to present a comment submission form violate the HIGS? I may have one popup with selections that goes to the final popup. Two popups back to back. This is more similar to a modal type of view than an alert or action sheet as described by the HIGS: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/MobileHIG/ModalViews/ModalViews.html#//apple_ref/doc/uid/TP40006556-CH11-SW1 under the section 'Using Modal Views'. Basically the type of view I'm shooting for is a combination of an alert with a custom view. It's sort of a mini view since it will be centered in the middle of the screen but not take up all of the viewing area. I'm fairly sure that is a violation however, but I'm looking for a few opinions on it.
I believe what needs to happen is use a modal view, which will cover the entire view.
Can't really say if having two of popups like this back-to-back would be a HIG violation, but Apple doesn't seem to have any problems with alert views with embedded controls. I've successfully used an alert view with an embedded UITextField and rating stars/slider.
It probably depends on how much you want to diverge from the looks of a standard alert view.

Why is a UITabBar considered Modal?

Reading the Apple documentation on the UITabBar states,
The most common use of a tab bar is to
implement a modal interface where
tapping an item changes the selection.
With my definition of Modal being:
A modal view is one that has to be
dismissed before you can do anything
else.
But that's not always the use case. I could be interacting with the content view of the UITabBar's first item/button, and that could allow me to reach another view.
OR, I could select another item/button from the UITabBar and reach yet another view.
So how is that considered Modal? (Or is my use case not Modal, and they are just saying, in general, its used Modally?)
I think "modal" here means different "modes".