Setting order of accesibility labels in subviews of a group, read aloud by Voiceover? - ios

I have a UITableView with cells based on an XIB with UIStackViews containing UILabels, in it. Labels have the texts A,B,C,D
(look at screenshot).
When I enable VoiceOver or use the Accesibility Inspector, It automaticallly groups the labels in a cell, reading all the texts on the labels - that's fine.
But I want it to change the order that it reads the sub-labels, when the superview is focused, so it's read like A,B,C,D - currently it's A,C,B,D.
I've tried a lot of things with no luck, like overriding the accesibilityElements, shouldGroup... and isAccessiblityElement. Every time I change something, i get either:
No change
Empty accesiblity label for the cell
The single labels become selectable (which is not what I wanted)
Any tips on how to fix this one? I guess I can't be the only one in the world with this problem, but apparently it's hard to find any info on recent iOS versions. I use 10.3 and Swift 3...

I gave up on the idea of profiting form iOS own concatenation of the subviews' accesibility labels and made a piece of code to handle it myself.
extension UIView {
open func updateCombinedAccessibilityLabel (elements: [AnyObject]) {
let accLabels: [String] = elements.map { $0.accessibilityLabel ?? "" }
accessibilityLabel = accLabels.joined(separator: ", ")
}
}
Then, when I set the labels' text values, I tell the view how to arrange the subviews' accesiblity order:
view.updateCombinedAccessibilityLabel(elements: [view.titleLabel, view.subtitleLabel, view.detailsLabel])

Related

UIsegmentedControl title appearance

HI, i set my uisegmentedcontrol's width manually, but when the width gets too small, the words becomes ...
Is that anyway that it won't behave in this way? Instead, i just want to show the text just like the picture shown below.
I'd suggest changing your design here and going for a different approach.
The design that you seem to want makes readability pretty much impossible.
Plus, what happens if I'm using your app and add another "Active Project". What happens if I have 10 active projects?
Take the fact that the UI does not work as a sign that you are using the wrong UI for the problem you are trying solve.
I'd suggest possibly just have the current project title here with a button to maybe present a list of projects to switch to... or something.
The text has been truncated. If you want it to fit your segment, you need to update the segment control size based on the text length. If you just want to get rid of truncation, you can use the following snippet. However, it's not recommended, as later Apple might change the UISegmentControl hierarchy.
for item in segmentedControl.subviews {
for subview in item.subviews {
if subview.isKind(of: UILabel.self) {
let _label = subview as! UILabel
_label.numberOfLines = 0
_label.lineBreakMode = .byWordWrapping
}
}
}

is there any method to check if both of the label text interupt together?

Now current i am placing the text into the table cell, however, i wish to detect that if two label , if one of the label text hit another one, (do something)
May i ask if the ios is able to achieve this with any method?
You can check if the label's frames intersect each other:
if CGRectIntersectsRect(label1.frame, label2.frame) {
// Do something
}

Change accessibility reading order of UINavigationBar [duplicate]

Is it possible to change the order in which the VoiceOver feature for accessibility in iPad reads out the elements, when the 'Two-finger Flick Down' gesture is done?
For the attached image, which contains 3 labels and a button, the VoiceOver reads the elements in the following way,
Label 1 -> Label 2 -> Button -> Label 3
Can the order be changed to,
Label 1 -> Label 2 -> Label 3 -> Button
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.
I tried setting the shouldGroupAccessibilityChildren to YES but it didn't work for me.
What did work for me was setting the accessibility label of the parent view directly (because I wanted all the items to be read in one go/one VoiceOver gesture).
[cell setAccessibilityLabel:[NSString stringWithFormat:#"%#, %#", cityLabel, temperatureLabel]];
The above snippet of codes is from Apple's documentation Enhancing the Accessibility of Table View Cells
In Swift, attaching an IBOutlet to the parent UIView, then setting shouldGroupAccessibilityChildren to true will suffice.
abc.shouldGroupAccessibilityChildren = true
I did note that if also setting isAccessibilityElement = true the grouping will not take effect. Similarly, checking the accessibility checkbox in the storyboard or xib will also prevent the grouping from taking place.
I think you can do it in the storyboard. The VoiceOver order is determined by the order of the views in the document outline.
Just drag and drop the views in the view hierarchy in the right order.

Accessibility for iOS, VoiceOver read order issue

Is it possible to change the order in which the VoiceOver feature for accessibility in iPad reads out the elements, when the 'Two-finger Flick Down' gesture is done?
For the attached image, which contains 3 labels and a button, the VoiceOver reads the elements in the following way,
Label 1 -> Label 2 -> Button -> Label 3
Can the order be changed to,
Label 1 -> Label 2 -> Label 3 -> Button
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.
I tried setting the shouldGroupAccessibilityChildren to YES but it didn't work for me.
What did work for me was setting the accessibility label of the parent view directly (because I wanted all the items to be read in one go/one VoiceOver gesture).
[cell setAccessibilityLabel:[NSString stringWithFormat:#"%#, %#", cityLabel, temperatureLabel]];
The above snippet of codes is from Apple's documentation Enhancing the Accessibility of Table View Cells
In Swift, attaching an IBOutlet to the parent UIView, then setting shouldGroupAccessibilityChildren to true will suffice.
abc.shouldGroupAccessibilityChildren = true
I did note that if also setting isAccessibilityElement = true the grouping will not take effect. Similarly, checking the accessibility checkbox in the storyboard or xib will also prevent the grouping from taking place.
I think you can do it in the storyboard. The VoiceOver order is determined by the order of the views in the document outline.
Just drag and drop the views in the view hierarchy in the right order.

UIScroll and its nested elements

I created a UIScrollView.
I set up the dimensions and then I am trying to add UILabels.
However the labels are all white text (annoying because I have to change the property per label).
Is there a way to make all labels (new ones that are dragged from IB to the view) have a default text color of black?
Edited to match comments
I want to use IB as much as I can. Therefore I want to drag UILabel from the Library palette to the UIView. When I do this, the UILabel is set to white (default). I want the default color to be Black. I know I can do this programatically but I am trying to avoid that unless I really really need to.
There's no easy way to do exactly what you want. But what you can do is create a label with the properties you want, store it somewhere on the drawing board but not in the view, then duplicate it each time you want a new label instead of dragging on a new one. You can duplicate easily using option+drag.
I think the short answer is "no, there's not an easy way to do what you're describing."
The easiest way I can think of would be to create all your UILabels (with the default setting of white text), then control-click them all and set their text color all at once – all the other ways are less convenient, or would essentially require that Apple open-source Xcode or UIKit so that we can get at their internals.
Yes, there is a way. You could loop the subviews of the target view such as:
UIView * targetView;
[...]
for(id subView in targetView.subViews){
if([subView isKindOfClass:[UILabel class]]){
[subView setBackgroundColor:clearColor];
}
}
why do the labels have to come from the object library? You could get the functionality that you want by dragging only one UILable from the library to your view set all the properties to the defaults that you want and hit copy(command+c) once. Now you can paste(command+v) your UILabel with the special property values as many times as you want, IBActions and outlets will also be retained in the copys.
If you plan to tweak more involved properties than font color and size, then I would suggest a more custom approach that will require only minimul coding before you do the bulk drag and drop work in IB.
Subclass a UILable in Xcode, set all of your properties just once in a simple return method and than call this method from both "init" and "awakeFromNib" Now go back to IB and do all your drag/dropping making sure that the labels are of your subclass.
However, it is my opinion that if you are doing this a lot, especially if you will be doing something similar again in the future, you will save a substantial amount of time and energy to implement this "label factory" in code. Its likely less code than you are imagining it will be and the kicker is that you can reuse it in the next app. anyway thats my 2cents, Good Luck

Resources