I've got a few custom UITableViewCells that I'm making accessible. I'm trying to get VoiceOver to read all the subviews when the cell is tapped. From my understanding, this is something you get for free when using or sublcassing UITableViewCell (Correct me if I'm wrong on that.)
The issue is in a few of my cells. In most of my cells, everything reads correctly. However, when I tap on a cell that contains a UITextField (or subclass of UITextField) it does not read the UITextField. It will read all the other elements (except the UIButton on one cell as well,) but will skip the text fields.
Does anyone know any reasons it would not read the UITextFields? And the one UIButton? Is there something special that needs to be done for those to be read? Or something special to be done to a UITableViewCell subclass that I haven't done?
Sorry for posting no code, I'm not really sure what code would be relevant to post since I don't see anything related to accessibility at all in the code. In the storyboard, it is selected as accessible for all elements I want read, however the UITextFields seem to ignore this setting.
What you want to do is create a custom cell class, and override the accessibilityLabel property of that class. Collecting all subviews accessibility labels. I'm on a windows machine now, so pardon if this doesn't quite compile, but you should get the idea.
#implementation MyCustomCellViewClass
-(NSString*)accessibilityLabel {
NSMutableString* result = [NSMutableString new];
for (subview in [view accessibilityElementViews]) {
[result append:subview.accessibilityLabel];
}
return result;
}
By including this as a property override, rather than setting accessibility labels at all potential points that it changes, you remove the concern of future devs overriding this behavior. You also gain automatic handling of dynamic elements within these cells, as the accessibility label will simply stay in sync with the accessibility information of the subviews. You can then include this class as a parent class of any future subclasses to trivially maintain this behavior. If any of your devs are dumb enough to remove this sub class from the inheritance tree you have bigger problems to deal with!
Make sure with this approach that your cell has the correct role. Whatever the active element of the cell is (be it a tab, link, button, etc) should be the role of your super view. The other elements are just informative.
Let's say your table cell has 4 elements a label, a button, a text field, a image view. All these elements are in the contentView of your tablecell.
To make sure the voice over reads all the 4 elements in your table cell, you need to tell the voice over that your contentview contains 4 elements.You can do this by adding all the elements in your contentView to the contentView's accessibilityElements Array.
contentView.accessibilityElements=#[label,button,textField,imageView];
Then the voice over will not skip any of these 4 elements.
Related
I'm having some issues with reusable cells in a UITableView. I have several types of cells, that I declare in the constructor.
My issue is that I have one particular type of cell that contains a UITextView and I have an issue when I scroll the table, the text within is lost. I need to save this text to the models that accompany the cells and then put the text back when the cell is used again.
How do I know that the cell is being moved away from? I have other types of cells, so I need a way to invoke some code to do the saving part on the scroll of the UITableView.
I hope that makes sense, if more is required, let me know.
Thanks.
Just save the text once it is changed to the model, check if any text is present and use that in tableView(_:cellForRowAt:)
For more help you will have to show us your code.
You can inherit UITextViewDelegate and in the textViewDidEndEditing(_:) check if the text view is edited, then you will be able to store the text in a variable or somewhere else and restore it whenever you are about to show that cell again.
If there is more than one text view, you might want to set an accessibility identifier for each kind, so you will find out which one did end editing.
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.
I need to design a view in which:
A lot of text is presented, with variable paragraph length
Specific paragraphs can be called into specific parts of the view (top, middle, bottom) either by the user (search, go-to) or programmatically.
Whenever a paragraph reaches a position in the view (let's say the middle) it triggers an event
Each paragraph can be tapped/selected to trigger events.
Each word in the paragraphs can be selected.
Bonus: the paragraphs are presented continuously, without breaklines (which excludes tableviews).
The text is fixed, and each paragraph is indexed (the data comes from an sqlite database).
I thought of three possible approaches, but each of them have its own problems I could not overcome:
A single textview. This would let me free to format the text the way I want, and work on the single words. On the other hand, I haven't figure out a way to act on the individual paragraphs. I wouldn't mind adding the index number for each paragraph on the side of the paragraph, but I don't know the best way to tag it (HTML?). Moreover i don't think there is something similar to scrolltoposition for anything other than a tableview.
Textviews for the individual paragraphs. I could use the index in the database to label each of them. Yet, as above, I don't think there is something similar to scrolltoposition...
Resizable textviews inside each cell in a tableview. This would let me work easily with the paragraphs and formats, but I don't think the text within the cell is selectable.
Any advice on how to solve those specific problems?
Any suggestion of an alternative way to achieve this?
The best approach, by far, is the UITableView. Everything you have listed is easily accomplished with the delegate methods of UITableViewDelegate, and UIScrollViewDelegate (of which a table view calls). The only issue with the tableview is the fact that UILabels cannot be selected within them. This is easily solved by not using a UILabel, but a UITextView. Simply disable scrolling on the text view, and disable editing (I'm not sure if disabling editing removes the selectability. If it does, override the UITextView and block edits from there).
1. Use UITableView
2. Create UITableViewCell with UIScrollView inside it
3. Override UIScrollView to disable editing
4. Add logic to UITableViewDelegate and UIScrollViewDelegate (of the table view) for the taps and position events
good luck,
ZR
I'm sure this is a very noddy question, but I just can't get anything useful from the manuals.
I've a UITextField embedded in a custom UITableViewCell. If I use a delegate for the UITextView - it just gives me the UITextView.
If I link the event to the ParerentViewController, it just gives me the ID of the UITextView.
What I want to do is handle the event at the UITableViewCell level. Can I get the events from this text control to feed to the parent, and handle them at the parent level.
I don't seem to even be able to find the parent cell from the UITextField that the handler gives me. How do I find out which cell within the table the UITextField is in when I'm trying to process the events.
I have to be missing something obvious, as I've done this in earlier (pre storyboard) versions, and I'm sure it wasn't this difficult.
Answered a similar question the other day. See the accepted answer.
How can I get index path of cell on switch change event in section based table view
This will let you handle the text changes in the cell and pass them on to the table view. In your case its a UITextView and not a UISwitch.
Add properties to the cell for anything you will need inside the block code when it is called.
Create a subclass of UITableViewCell and implement the textField delegates inside the subclass. The code is lengthy but if you want I can post it when I get time.
I currently have a UITableView that contains editable UITableViewCells. When a cell goes into edit mode, i use the willTransitionToState and didTransitionToState to show/hide a UITextField when the cell goes into edit mode. The problem, is if I have invisible cells, the willTransitionToState/didTransitionToState does not get called when they become visible... so the cells still look like they are in edit mode. Does anyone have a suggestion to fix this?
Hiding/unhiding subviews of your UITableViewCell do not constitute a change of state, that's why those methods don't get called.
Depending on your implementation, you could invoke those methods yourself when hiding/unhiding. But in general, you should implement the hiding/unhiding logic in those methods, not outside of them, e.g. a change of state leads to the change of the subviews, not vice versa.
For more concrete answers you should provide samples of your code and get more concrete on what you are trying to achieve.
Peter