How do I set the accessibility label for a particular segment of a UISegmentedControl?
I'm just getting started with KIF myself, so I haven't tested this, but it may be worth a try. I'm sure I'll have the same issue soon, so I'd be interested to hear if it works.
First, UIAccessibility Protocol Reference has a note under accessibilityLabel that says:
"If you supply UIImage objects to display in a UISegmentedControl, you can set this property on each image to ensure that the segments are properly accessible."
So, I'm wondering if you could set the accessibilityLabel on each NSString object as well and be able to use that to access each segment with KIF. As a start, you could try creating a couple of strings, setting their accessibility labels, and using [[UISegmentedControl alloc] initWithItems:myStringArray]; to populate it.
Please update us on your progress. I'd like to hear how this goes
How to Focus Accessibility On A Particular Segment in A UISegmentedControl
I created a blank project as follows to reproduce the problem:
The solution is taking the selectedIndex
to display the selected segment and providing the appropriate segment object for the VoiceOver notification: easy, isn't it?
I naively thought that getting the subview in the segmented control subviews array with the selectedIndex
would do the job but that's definitely not possible because the subviews can move inside this array as the following snapshot highlights (red framed first element for instance):
The only way to identify a unique segment is its frame, so I pick up the segmented control index and the frame of the selected segment to pass them to the previous view controller.
That will allow to display (index) and read out (frame that identifies the object for the notification) the appropriate selected segment when this screen will appear after the transition.
Hereafter the code snippets for the view controller that contains the 'Next Screen' button:
class SOFSegmentedControl: UIViewController, UpdateSegmentedIndexDelegate {
var segmentIndex = 0
var segmentFrame = CGRect.zero
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let segueName = segue.identifier {
if (segueName == "SegmentSegue") {
if let destVC = segue.destination as? SOFSegmentedControlBis {
destVC.delegate = self
destVC.segmentIndex = segmentIndex
destVC.segmentFrame = segmentFrame
}
}
}
}
@IBAction func buttonAction(_ sender: UIButton) { self.performSegue(withIdentifier: "SegmentSegue", sender: sender) }
func updateSegmentIndex(_ index: Int, withFrame frame: CGRect) {
segmentIndex = index
segmentFrame = frame
}
}
... and for the view controller that displays the segmented control:
protocol UpdateSegmentedIndexDelegate: class {
func updateSegmentIndex(_ index: Int, withFrame frame: CGRect)
}
class SOFSegmentedControlBis: UIViewController {
@IBOutlet weak var mySegmentedControl: UISegmentedControl!
var delegate: UpdateSegmentedIndexDelegate?
var segmentFrame = CGRect.zero
var segmentIndex = 0
var segmentFrames = [Int:CGRect]()
override func viewDidLoad() {
super.viewDidLoad()
mySegmentedControl.addTarget(self,
action: #selector(segmentedControlValueChanged(_:)),
for: .valueChanged)
mySegmentedControl.selectedSegmentIndex = segmentIndex
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print(mySegmentedControl.subviews)
let sortedFrames = mySegmentedControl.subviews.sorted(by: { $0.frame.origin.x < $1.frame.origin.x})
for (index, segment) in sortedFrames.enumerated() { segmentFrames[index] = segment.frame }
if (self.segmentFrame == CGRect.zero) {
UIAccessibility.post(notification: .screenChanged,
argument: mySegmentedControl)
} else {
mySegmentedControl.subviews.forEach({
if ($0.frame == self.segmentFrame) {
UIAccessibility.post(notification: .screenChanged,
argument: $0)
}
})
}
}
@objc func segmentedControlValueChanged(_ notif: NSNotification) {
delegate?.updateSegmentIndex(mySegmentedControl.selectedSegmentIndex,
withFrame: segmentFrames[mySegmentedControl.selectedSegmentIndex]!) }
}
The final result is as follows:
- Double tap to go to the next screen.
- Select the next element to focus the second segment.
- Double tap to select the focused element.
- Get back to the previous screen thanks to the
Z gesture
natively known by iOS with the navigation controller. The delegate passes the index and the frame of the selected segment. - Double tap to go to the next screen.
- The segment that was formerly selected is read out by VoiceOver and still selected.
You can now Focus Accessibility On A Particular Segment in A UISegmentedControl following this rationale.
I try to avoid "hacky" solutions (like the one I just referenced), but I'm willing to consider anything.
Unfortunately, this solution is a hacky one... sorry. However, it works and I couldn't find another one anywhere else: see it as a personal fix unless you get a cleaner one to share? ;o)
UPDATE... That's probably a topic for a second question.
I can't reproduce the behavior of your update: if you create a dedicated topic for this problem, please add the most detailed code and context so as to provide the most accurate solution.
VoiceOver with UISegmentedControl in Swift
In line with Andy's comment I coded:
segmentedControl.subviews[0].accessibilityLabel = "Seg 2";
segmentedControl.subviews[1].accessibilityLabel = "Seg 1";
segmentedControl.subviews[2].accessibilityLabel = "Seg 0";
Not the best, note subviews are reverse to appearance, but appears to be the only way at this time.
Greg
How do I set the accessibility label for a view in xcode4's interface builder?
To set the variable programmatically you can use its property like this:
UIButton *someButton = [[UIButton alloc] init];
someButton.titleLabel.text = @"Your Button's Text";
someButton.accessibilityLabel = @"SomeNSString";
In the InterfaceBuilder -- built into XCode 4 -- you just have to select the UI item you want to have an accessibility label. The "Identity Inspector", in the "Utility"-pane, offers a textfield where you can enter any label-text you want.
Localized UISegmentedControl
Use - (void)setTitle:(NSString *)title forSegmentAtIndex:(NSUInteger)segment
Related Topics
Multiple Localized .Strings Files in iOS App Bundle
How to Calculate Current Location in Watchkit Extension
Nspredicate to Match "Any Entry in an Nsdatabase with Value That Contains a String"
How to Add Firebase to Today Extension iOS
How to Get MAC Address from Cbperipheral and Cbcenter
How to Change an iOS Device Volume Programmatically
How to Overlay One Video on Another in iOS
Rec iOS Conversations. Where to Start
How to Use Nsurlsession to Determine If Resource Has Changed
How to Emulate Nfc Cards in iOS 13
Two Buttons Inside Hstack Taking Action of Each Other
Could Not Cast Value of Type 'Uiview' (0X112484Eb0) to 'Skview' (0X111646718)
How to Detect Tap on Clear Part of Uitableview
Today Extension View Flashes When Redrawing
How to Play Multiple Audio Files Simultaneously
iOS Facebook Sdk 3.1 Retrieve Friend Birthday Returning Null