How can I enable VoiceOver for webview content on tableview - ios

Normally, VoiceOver correctly reads web contents loaded with WKWebView and it is possible to read buttons and links.
However, when I added WKWebView on UITableViewCell and displayed in UITableVIew, VoiceOver could not recognize it.
According to the tableview document of apple, in order to make each content on UITableViewCell recognized by VoiceOver separately,
It is necessary to set isAccessibilityElement of cell to false and set isAccessibilityElement of view to be recognized to be true.
but if isAccesibilityElement ofWKWebView is set to true, view itself is focused and we can not recognize the inside web contents.
Also, when VoiceOver was enabled for the first time after loading the Web content, it performed strange behavior that Web content could be recognized.
I suspected the problem of VoiceOver content recognition timing, I tried running
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil)
or
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil)
after loading the web content, but it did not get a good result.
Is there a good way to handle contents in wkwebview on tableView to VoiceOver?

So, I'll explain the behavior you're seeing. Essentially, VoiceOver will only focus the first accessibility element in a tree. So any view that is an Accessibility Element will not have its children that are accessibility elements be focused.
Now as for your situation, I'm curious as to your scenario. I find it likely that you need to provide more detail. When I picture a tableview, I picture multiple WKWebViews in one view, which would be weird indeed.
The typical markup for a webview would be to just have NOTHING set as an accessibility element, and let the WebView determine which elements within are accessible. WKWebView should take care of reporting HTML content as proper native accessibility elements for you. To do anything else is going to corrupt what WKWebView is going. HOWEVER, if you have multiple webviews in one app, this may muck things up. Ultimately, if it didn't work the way I outlined (just by leaving things alone, and marking everything as "not" an accessibility element), this would be a bug, but a bug that you would have to deal with.
The solution THEN becomes overriding the UIAccessibilityContainer protocol for your webview, and providing custom feedback for it. Not ideal, would be painful. More details would help, but at least now you can understand a little more about what is going on.
Another simple solution would be, if the content in your webview is very simple, you could set accessibility element to true, and provide a description of the content for the entire webview through the accessibilityLabel, accessibilityValue and accessibilityTraits. Just be sure you catch all of the information, and that any actions are still actionable!

Related

How to make voice over reads only visible tableview cells

I implemented the voiceover for my app ,in message detail screen when i play the voiceover for whole screen it starts reading the cells which are not visible in the cell, i want to read only visible cells like iPhone default message app.
Assuming you are setting the isHidden flag on your views and that is not preventing them from being read via VoiceOver, you might try setting isAccessibilityElement=false for the hidden items, or using accessibilityElementsHidden.
(I haven't used accessibilityElementsHidden before, but based on the description it sounds like it turns off accessibility (VoiceOver) for the subviews of a vieww.)

How can I get IndexPath of currently selected tableviewcell by voice over?

I'm using Voice Over in my application. I'm having hard time to figure out which table cell is currently selected when voice over is on. How can I know whenever user initiates single tap or navigate through any tableviewcell?
These are the things you can try:
use the UIAccessibilityFocusedElement global function
override accessibilityElementDidBecomeFocused and accessibilityElementDidLoseFocus on the cell
observe the UIAccessibilityElementFocused notification in NotificationCenter in situations where you need it (e.g. when the view controller for the table in question is showing)
Also what element will report focus will most probably depend on whether your UITableViewCell has isAccessibilityElement set to true or false.
While the above will probably help you with literally what you asked, it is also possible that your overall approach to accessibility in this situation might be wrong if you need the above information. If you share more info on the bigger picture / motivation what you are trying to achieve, it might turn out that the information about focused element might not be needed at all and that another solution is more proper.
If what you need is to add a hint for swiping, you can simply set accessibilityHint on the proper element (if you set isAccessibilityElement = true on the whole cell, then set that on the whole cell, otherwise try setting it on the label that VoiceOver reads in the cell), e.g. when you configure the cell for display (usually in tableView(_:cellForRowAt:)). In such case, you will not need to observe which element is focused, and simply let VoiceOver read hint available on that particular element/cell.

XCode autocomplete

I'm new to IOS development, I have a few questions.
1) What's the purpose of property rowheight on table view cell, I mean it does nothing even if I change its value, it always takes the value from its parent view i.e a tableview property rowheight? It visually changes in the IB but nothing happens when I run the app.
2) What's the purpose of Content View why is it even there? Let's say If I have to make some image equal to the height of the cell it restricts me. Or is there any way a content view can be changed to be equal to the cell height & width? I have to put constraints on the image in relation with the cell which is not the immediate parent of the image and I don't know if this is the correct way to do it.
3)How does Xcode Autocomplete works? like if I want to write a function tableview(_:tableview didselectrowwithindex:IndexPath) and I type tableview it shows a list, what to do next? I mean I can't type the whole fucntion with params or find the func in the huge list.
The height of the cell set at the IB is primarily used for simulation, the views described at IB are normally resized when actually used. E.g. you can set rows height to be 100 for the table view, 30 for some of the cells and keep the whole controller simulating a nice screen of iPhone 6. The same view will be used for all devices and will be scaled accordingly as well as the cells with the help of your delegate.
The content view is there for the reasons directly related to your additional requests. It holds all the content while there other views that accompany your content and are part of the cell like separators, accessory views, slide action views. Without a content view the responsibility of managing all the additional parts would most likely fall on you as a developer and while you might think that that is fine at the simple layouts, a simple enhancement to it would make a huge impact.
Fuzzy autocompletion at Xcode seems to be something Apple is working on now. If you can't wait and find it too difficult to navigate through the list, there are Xcode plugins available that provide fuzzy autocompletion.
Answering the question in the topic:
example: tableview(_:tableview didselectrowwithindex:IndexPath)
if you write tableview it will show all the symbols that start with tableview. For functions, it will show all the functions sorted by the second parameter name (didSelectRowWithIndex).
[EDIT]
it will autocomplete as far as the answer is unique and then show you a list full of options. I don't know any tricks to skip looking through the massive list. But after a while you'll know what you're looking for and it gets faster.
[\EDIT]
when you press tab, it
by the way: the delegate functions names start with the name of the object they're related to.
So UITableViewDelegate functions start with tableview.
as for your first two questions there are tons of answers for those questions on SO. This one seems closely related to yours.

Dynamically Change isAccessibilityElement

I've got a bit of a weird situation. I need to have an element not be read out by VoiceOver when I use the 2 finger swipe method, but to be read when tapping on it still.
The object is part of a TableView cell, and I've given the TableView cell its own accessibilityLabel, because it contains two interactive elements, one of which doesn't actually need to be read when tapped on, so I've disabled its accessibility property.
However, my other one needs to be read still when tapped on. The issue is, it's already being read as part of the cell's accessibilityLabel, and then it is read again because it is still an accessible element. Is there any way to differentiate between why VoiceOver is reading an element? Or to dynamically change the accessibilityLabel?
You can dynamically change accessibilityLabel simply by assigning it or overriding the method on the accessible view. However, you shouldn't rely on VoiceOver respecting the change in real time.
Users can navigate via tap or swipe and expect elements to persist regardless of how they were reached. In general, I discourage clever solutions that assume how users interact with VoiceOver.
I'd encourage you to either override the cell summary to omit the label or disable accessibility on the label and leave the content in the cell summary.

UICollectionView Section Headers as Accessibility Headers

I have two questions regarding accessibility and UICollectionViews that I'm hoping to get some expert help with. The other question, regarding Voice Over read order, is here. I've created a sample project demonstrating both issues.
I have a UICollectionView where I'm providing custom section headers. These section headers are accessibility elements and have the accessibility trait UIAccessibilityTraitHeader set. When Voice Over is enabled, and the user is swiping horizontally through the collection, the header is announced properly, and it is even declared as a header. However, if the user swipes up or down to the next header, Voice Over will only jump to another header if it is visible. I'm assuming this is because when a view isn't visible in a collection view, it's removed from the view hierarchy and Voice Over no longer knows it exists.
You can pull this example project, run it, enable voice over, and use the dial to set the swipe up/down to headings to view the issue.
Is there a way I can allow the user to jump to a header that is not currently visible? Any help would be greatly appreciated.
You might have to use the scrollToItemAtIndexPath:atScrollPosition:animated: property of the UICollectionView to scroll the header into view before VoiceOver can read it.
You can find out which indexPath you are currently at via indexPathForItemAtPoint: using the position of where they touched within the collection view and then you know which section comes after.

Resources