UICollectionViewFlowLayout Voice Over reads items out of order with Flow Layout - ios

I have two questions regarding accessibility and UICollectionViews that I'm hoping to get some expert help with. The other question, regarding section headers, can be found here. I've created a sample project demonstrating both issues.
I have a UICollectionView using UICollectionViewFlowLayout that contains items of variable height. UIFlowLayout centers the elements on each row vertically. Unfortunately, when Voice Over is enabled, it seems to favor elements that are placed higher vertically, causing it to read items out of order.
You can pull this example project, run it, enable voice over, and swipe through the items to see the issue. It creates cells with random heights, so it will very likely read the cells out of order.
Is there a way I can make the collection view advance through the items sequentially? I feel like that is the only way that makes sense, but I can't find a way to enforce that behavior. Setting the collection view to group child views doesn't seem to help. Any help would be greatly appreciated.

Taken from Accessibility for iOS, VoiceOver read order issue
The quickest way to achieve this for your example is to place the three labels in a transparent UIView subclass to serve as a container for your labels. This subclass will have to be properly setup to let VoiceOver know how to interpret it. If your deployment target is iOS6 then you can simply answer the "should group accessibility children" question in this subclass.
-(BOOL)shouldGroupAccessibilityChildren{
return YES;
}
For below iOS6 it would be more complicated, except that your UIView container subclass would contain only UILabels which are accessibility elements. You could implement it like this:
-(BOOL)isAccessibilityElement{
return NO;
}
-(NSInteger)accessibilityElementCount{
return self.subviews.count;
}
-(id)accessibilityElementAtIndex:(NSInteger)index{
return [self.subviews objectAtIndex:index];
}
-(NSInteger)indexOfAccessibilityElement:(id)element{
return [self.subviews indexOfObject:element];
}
I have tested this example code and it does what you are looking for, if you need any clarification please add a comment. Always happy to help make things more accessible.

Related

How i can use multiple nib files with multiple arrays?

I am creating my iOS app, and i during that , now i have to build scrollable screen where there is image view, labels, collection view, Reviews etc (Prototype Image is attached). I am wondering is it possible to make that type of screen with UITable view using multiple Nib files? (If it is possible, kindly guide me as how i should use multiple Nib files with multiple arrays). And , if it is not possible, how else i can go for it? Kindly guide me, and sorry if thats a duplicate because i have searched but i was not able to find any good answer.
There are several approaches that you can do.
If you want to use UItableview, then you need to create multiple
UITableviewCells, where each cells is based on the section of the design. Then you can load it by using array, as you logic stated above. For example indexpath[0] you'll load the cell with the picture(lets call this pictureCell), then indexpath[1] you'll load descriptionCell, and so on.
The other approach is using Scrollview, with several UIViews on a vertical stackview. And then you'll create a UIView Subclass based on the section of the design. This is usually my go to solution.
I'm not sure what "array" is refering to here, but by the look of your screenshot, I would go with a StackView inside a UIScrollView, or something like that. No need for a UITableView if you don't have a repeting pattern, you can just stack multiple views in a scroll view.
I hope it's clear enough.

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.

VoiceOver not reading UITextField subviews

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.

iOS Design implementation recommandations

I would like to know how to handle, for my iOS app, the following situation:
I have to deal with something like this (basicly this is an article with comments, received from a server):
=- Text and Images -=
=- UIWebView -=
=- List of Comments -=
Now, I came up with two solutions:
Have the content above the list of comments wrapped in a UIScrollView, and create Views for each and everyone of the comments (don't know many of them could be), and
Make the list of comments a UITableView, and the above content its Header.
Which of these (or possibly another if you have any recommandations) should I choose? It may look not very important, but I would like to know this, so I could use the idea in further developing.
I would use a UITableView with a custom UITableViewCell wich holds the comments.
It will definitely have a better performance the UITableView than the UIScrollView since the UITableView re-uses the cells.
Using a UITableView you will just have to worry about customising the cells for the comments.
Otherwise if you want to use the UIScrollView in case you have a lot of comments you will have to create manually a way to reuse them which is what the UITableView does.
If you want something like facebook, so that the context + comments both are movable,then go with option 2.
But, if you want content always at the top, go with option 1.
Indeed, UITableView is a subclass of UIScrollView.
And If you think you might have many comments like (50+),
If you use scrollView, then you should have to supply scrollView with those number of UIView objects.
But, if you use tableView, it perfectly reused already created views.So evenhough you have 1000+ comments, it just uses 5 UIView objects

Custom UICollectionViewLayout animation issues

I developed a custom UICollectionViewLayout to handle some advanced layout requirements on a clients application what seems to work really well.. Until I start trying to use animations.
I took some time out of work to document and make it a bit more flexible so it can be found here: https://github.com/liamnichols/LNCollectionViewPagedLayout.
Its purpose is to page the content onto new pages if it will not fit on the previous page to ensure that the content does not get cut across two pages and it seems to handle this OK.
I noticed from the start that there where animation issues with it however I never needed to use animations originally so didn't attempt to investigate/fix although now its become a requirement that a UICollectionViewCell can expand revealing some more content and when I attempt to use any form of animation methods (reloadRowsAtIndexPaths:, performBatchUpdates:completion: ect) I always get very strange behaviour ranging from crashes (view argument is nil) to messed up layouts.
Currently my layout works by creating a dictionary of UICollectionViewLayoutAttributes on prepareLayout by asking the delegate for the size of each cell then running some logic to see if it will fit or not and so on...
When the layoutAttributesForElementsInRect: method is called, it can then simply query the dictionary and fetch an array of attributes that are relevant for that rect.
First off, is that the best way to go about creating this layout? I found it very hard to find documentation on creating custom layouts to meet my needs and ended up looking at other open source libraries for pointers on what to do.
Secondly, I haven't implemented the initial/final layout attribute methods as I cannot figure out how to correctly use them. Is this the reason I'm having issues or are these optional?
Any help or pointers to correctly creating UICollectionViewLayouts would be great.
For issues with expanding cells (or just cells changing size in general), this answer may be helpful. The short answer is that the default implementation of initialLayoutAttributesForAppearingItemAtIndexPath: (and, in general, all of the initial/final layout attribute methods) doesn't always return the correct frame and you've got to override this method and fix the errors.
Debugging these types of issues is fairly straightforward. Start by logging the attributes being returned with something like this
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
NSLog(#"indexPath=%#, attributes=%#", itemIndexPath, attributes);
return attributes;
}
and determine when the frames are incorrect. From there you can come up with an approach to correct the errors. Thats about as detailed as I can get without knowing more specifics.

Resources