When using ECSlidingViewController2, How can we prevent the under left menu from being tapped with VoiceOver on and the menu is under the top view? Try the BasicMenu example. When on the Home view, you can tap the options on the menu underneath.
If you dont want the voice over to read it, then make it inaccessible. Set the isAccessibleElement to NO.
This is a master switch for whether the element is accessible or not. UIViews and any custom direct subclasses of it are not accessible by default, whereas UIControls are. Elements which are not marked as accessible will be ignored by VoiceOver, and will be skipped when the user is navigating between accessible elements.
- (BOOL)isAccessibilityElement {
//if this is YES, VoiceOver won't continue to look for accessibility elements in this view's subviews
return NO;
}
Also you can set this to any UIView in your app.
Related
I have a view controller with this layout (note that yellow and table views are siblings):
I want the yellow view to act as a container, so I'm doing this in viewDidLoad:
yellowView.isAccessibilityElement = true
view.accessibilityElements = [yellowView!, tableView!]
When in Voice Over, I select "Containers" from the accessibility rotor and expect to be able to swipe up and down to move from the yellow view to the table view and back again:
Yellow (swipe down) → TableView (swipe down) → Tabbar (swipe up) → tableView (swipe up) → Yellow
However, this is not the case - after the tableView gains focus, swiping up does not move focus to the yellow view, it just stops there. Swiping down, moves to the tabbar - it seems that my custom view is ignored as container.
I have experimented with many combinations of adding superviews and setting isAccessibilityElement = false to them, but nothing seems to work.
Does anybody know how to solve this?
it seems that my custom view is ignored as container.
Apparently, only native elements may be recognized as containers for the rotor.🤨
I tried by creating an UIAccessibilityElement inside a view defined as its container with an accessibilityContainerType but no results.🤯
I never use the rotor with the container item but this issue has aroused my curiosity. 🤓
I looked into this problem and found out an interesting answer that highlights the same a11y trait value for all the native containers... those that are analyzed by VoiceOver as such at least.
Override the trait value of your specific containers as follows for instance:
override var accessibilityTraits: UIAccessibilityTraits {
get { return UIAccessibilityTraits(rawValue: 0x200000000000) }
set { }
}
This is a workaround because nothing else seems to be done for custom containers but I'm not a big fan of using raw values that may change or may not be used in a future release.
Anyway, following this rationale, you can now setup accessibility containers so that gestures work properly with the VoiceOver rotor. 👍
Did you set an accessibilityLabel on the yellowView or try changing the accessibilityContainerType = .semantic?
I think VoiceOver is not finding yellowView because the rotor is looking for UIAccessibilityContainer but the default container type is .none for UIView. However, a UITableView has a default container type of .semantic.
I've created a custom accessibility rotor to allow navigating through custom annotation views following the example djibouti33 provides here: Create a custom VoiceOver Rotor to navigate MKAnnotationViews. It works after selecting the custom rotor, but the rotor for the MKMapView always defaults to some other selection. The ability to navigate through the custom annotations makes the most sense in the context of the App (i.e. place priority on navigating through the App-specific annotations). Is there a way to have the custom rotor selected by default?
Related to this, I think it would also be more intuitive to have VoiceOver state the option to select the custom rotor, but when the MKMapView is touched is VoiceOver always states "Use the rotor to select points of interest". Changing the map view accessibilityHint like this had no effect:
mapView.accessibilityHint = "use the rotor to access alerts"
Is it possible to change what VoiceOver speaks when a MKMapView is selected?
When a custom rotor is created, it's added to the bunch of rotor actions selected by the user in his settings.
Unfortunately, user settings is kind of private box you cannot access in this case, that's why a custom rotor cannot be a default selection, it's a willingly user choice.
About the second question, your mapview is a container and, as a parent view that wants to show its children as accessible elements, its isAccessibilityElement property is false meaning that label or hint won't be analyzed by VoiceOver.
If you want to reach the accessible elements inside your map, your MKMapView itself will be never selected (only its elements) and then VoiceOver won't read out anything for this particular case because it's an invisible element for it.
According to your application presentation, you may post a notification while loading the view or add an accessible element before your map indicating that the rotor may be used to reach some information for instance.
I’m implementing accessibility in a custom UITableViewCell class. I have a fairly simple overflow menu with a couple of buttons inside it, which are hidden until an ellipsis button is pushed that slides open and closes the overflow.
In my cell's initialiser I’m setting the accessibilityElementsHidden of my overflowContainer to YES. This seems to work, when scrolling through using VoiceOver, those views are skipped.
Then, when opening the cell, in the completion handler of the UIView animation, I set that same accessibilityElementsHidden of the same overflowContainer to NO. This doesn’t seem to have any effect, those elements are still skipped.
I’ve also tried posting UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil) before / after / when changing the accessibilityElementsHidden BOOL, but this also appears to have no effect on the situation.
Basically I’d like to toggle accessibilityElementsHidden on a couple of UIView instances at a specific point. Could anyone let me know what I may be doing wrong?
Here’s the code I fire when the overflow opens:
- (void)cellOverflowDidShow:(MyCell *)cell
{
self.overflowContainer.isAccessibilityElement = YES;
self.firstButton.isAccessibilityElement = YES;
self.secondButton.isAccessibilityElement = YES;
self.thirdButton.isAccessibilityElement = YES;
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.firstButton);
}
I fire the opposite when closing the cell (set all to NO and post notification again). And when initializing the cell, all I set is:
self.overflowContainer.isAccessibilityElement = NO;
Absolutely no idea why it shouldn’t be working, it appears I’m doing everything 100% correctly. If I don’t set the line in the initializer, the buttons all appear accessible (all the time). So it appears that the first call, be it YES or NO, works, but any subsequent ones are ignored.
In the visible state, you declare the overflow container to be an accessibility element. Thus, VoiceOver will allow the user to focus it rather than navigate child elements. Instead of toggling whether it's an accessibility element, keep self.overflowContainer.isAccessibilityElement set to NO and toggle the accessibility of its children, firstButton, secondButton, and thirdButton.
A shorthand for setting the accessibility of child elements is accessibilityElementsHidden. Try setting self.overflowContainer.accessibilityElementsHidden to NO when the view appears and YES when it disappears.
You may still need to trigger a layout change notification, regardless.
I just have a knowledge question about UIButtons / iOS in general.
Let's say you have a UIButton. You set the 'hidden' property to YES. This makes it no longer visible in view, right? But I noticed that while it's no longer visible, it is also no longer clickable either. So, does this mean that setting hidden = YES also sets enabled = NO?
Just curious. Thanks y'all.
UIButton and all controls inherits common properties from UIView like hidden, backgroundColor, etc.
Class reference of UIView says if any view is hidden then it will not receive input events
Class reference of UIView says:
A hidden view disappears from its window and does not receive input
events. It remains in its superview’s list of subviews, however, and
participates in autoresizing as usual. Hiding a view with subviews has
the effect of hiding those subviews and any view descendants they
might have. This effect is implicit and does not alter the hidden
state of the receiver’s descendants.
you can find this over Here.
It does. Setting the buttons hidden property to YES will disable any user interaction. This is true for other UI elements as well as just UIButton.
Yes you can't touch button when it is hidden.If you wanna touch it then you must make it btn.hidden = NO;. Hidden means disable the user interaction.
Not sure. Best way to find out would be an NSLog returning button.hidden
A single swipe gesture is intended by Apple to move the VoiceOver cursor through screen items in order but mine don't because the user can move them around!
My main view has a set of buttons and labels, however it also has two collections of custom subviews, let's call the instances SVA1 to SVA9 & SVB1 to SVB9 in 'ascending order' from left to right. That is, SVA is one custom UIView class and SVB is the 2nd. When I drag, say, SVA3 to the current position of SVA6 then I end up with an order of SVA1, SVA2, SVA4, SVA5, SVA3, SVA6, SVA7, SVA8 & SVA9. The collections are 'linked' so that that same order would now also be mirrored in the SVB subview collection via my code.
My problem is that swiping to the right, expecting VoiceOver to read out my items as I see them on screen results in a different order. It gets quite a lot of them right but then will suddenly move the VoiceOver cursor from the first collection to the 2nd or change its direction. After a move my code is aware of the new order of all the subviews but I'd like to be able to get that information to VoiceOver.
Each custom subview is an accessibilityElement. Is there a way that I can tell VoiceOver to read back my items in the order I'd expect? I've come across the -accessibilityElementAtIndex: method but don't see whether or how that fits with my situation.
Thank you.
If you want to change the order then accessibilityElementAtIndex: and the rest of the UIAccessibilityContainer protocol is what you are looking for.
Assuming that you have an array called accessibleElements that store the elements in the order you want them to appear.
- (NSInteger)accessibilityElementCount {
return self.accessibleElements.count;
}
- (id)accessibilityElementAtIndex:(NSInteger)index {
return self.accessibleElements[index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element {
return [self.accessibleElements indexOfObject:element];
}
The container can't be a accessibility element itself so you should also override isAccessibilityElement
- (BOOL)isAccessibilityElement {
return NO;
}