I'm facing an accessibility issue, where when I call UIViewController.addChild(_:) and pass in another instance of a UIViewController, the VoiceOver focus is jumping to the "Back" button in the navigation bar. How might one go about avoid this behaviour and having the accessibility/voiceover focus remain where it was at the time of adding the child?
Accessibility
RSS for tagMake your apps function for a broad range of users using Accessibility APIs across all Apple platforms.
Posts under Accessibility tag
124 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I am trying to get a Notification if Guided access is enabled or disabled on the VisionPro.
For doing so you would normally just call:
NotificationCenter.default.addObserver(forName: UIAccessibility.guidedAccessStatusDidChangeNotification, object: nil, queue: .main){ noti in
print("guided access did change")
}
and this works fine on iOS devices.
But running the exact same code in Vision os Results in not getting a notification at all, even though Guided Access gets enabled or Disabled.
For testing i ran a simple default app, that works perfectly on both os types.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.onAppear{
print("is appeairng")
NotificationCenter.default.addObserver(forName: UIAccessibility.guidedAccessStatusDidChangeNotification, object: nil, queue: .main){_ in
print("guided access did change")
}
}
.padding()
}
}
But as said it prints "guided access did change on iOS" but not on the Vision Pro.
I'm trying to include Apple's Personal Voice feature in an app I'm working on, but I want to use a button or toggle to request access, rather than firing the request on first launch. The problem is that, if AVSpeechSynthesizer is used during the same session, before Personal Voice is authorized, the app has to be restarted to use the feature.
Here is a basic example that demonstrates the issue on my iPhone (running 18.1 beta, but the issue was present at least in 18.0, maybe before):
import AVFoundation
import SwiftUI
struct TestView: View {
let synthesizer = AVSpeechSynthesizer()
@State private var personalVoices: [AVSpeechSynthesisVoice] = []
var body: some View {
VStack(spacing: 100) {
Text("Personal Voices Available: \(personalVoices.count)")
Button {
speakUtterance(string: "Hello, world!")
} label: {
Image(systemName: "hand.wave.fill")
.font(.system(size: 100))
}
Button("Fetch Personal Voices") {
Task { await fetchPersonalVoices() }
}
}
}
func fetchPersonalVoices() async {
AVSpeechSynthesizer.requestPersonalVoiceAuthorization() { status in
if status == .authorized {
personalVoices = AVSpeechSynthesisVoice.speechVoices().filter { $0.voiceTraits.contains(.isPersonalVoice) }
}
}
}
func speakUtterance(string: String) {
let utterance = AVSpeechUtterance(string: string)
if let voice = personalVoices.first {
utterance.voice = voice
} else {
utterance.voice = AVSpeechSynthesisVoice(language: Locale.preferredLanguages[0])
}
synthesizer.speak(utterance)
}
}
If you tap the hand symbol first (before authorizing Personal Voice), you'll probably notice that the Personal Voices Available number never increases. If you authorize Personal Voice before tapping the hand symbol, it should speak using your Personal Voice as expected.
The example code is mostly taken directly from this WWDC23 video (Personal Voice info begins around the 10-minute mark).
Does anyone have any idea what could be causing this?
Note: Personal Voice can't be tested in Simulator. The code will need to be run on a physical device that has Personal Voice set up, to test.
I can't figure out if I've found a VoiceOver problem with Swift Charts or if I'm doing something incorrectly.
I have a loop within a loop showing 2 sets of data in the same chart.
If I touch a month then VO correctly says there are two data series. But if I keep swiping down only data from the first series is read.
ChatGPT said try referencing the outer loop and sure enough that worked if it done in BOTH the label and value.
It sounds really awkward though. For example, "High 89 degrees F High October".
Below the "bad" chart only says something such as "92 degrees F October" when swiping down. The "good" chart will read the high and low temperature data.
VStack {
headerText("BAD")
Chart {
ForEach(processedMonthlyInput) { oneMonth in
ForEach(oneMonth.temperatures, id: \.month) { element in
LineMark(
x: .value("Month", element.month, unit: .month),
y: .value("Temperature", element.tempVal.converted(to: .fahrenheit).value)
)
.accessibilityLabel("\(element.month.formatted(.dateTime.month(.wide)))")
.accessibilityValue(Text("\(element.tempVal.converted(to: tempUnit).formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))))"))
}
.symbol(by: .value("Type", oneMonth.theType))
.foregroundStyle(by: .value("Type", oneMonth.theType))
.interpolationMethod(.catmullRom)
}
}
.frame(maxHeight: paddingAmount)
.padding(.horizontal)
headerText("GOOD")
Chart {
ForEach(processedMonthlyInput) { oneMonth in
ForEach(oneMonth.temperatures, id: \.month) { element in
LineMark(
x: .value("Month", element.month, unit: .month),
y: .value("Temperature", element.tempVal.converted(to: .fahrenheit).value)
)
.accessibilityLabel("\(oneMonth.theType) \(element.month.formatted(.dateTime.month(.wide)))")
.accessibilityValue(Text("\(oneMonth.theType) \(element.tempVal.converted(to: tempUnit).formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))))"))
}
.symbol(by: .value("Type", oneMonth.theType))
.foregroundStyle(by: .value("Type", oneMonth.theType))
.interpolationMethod(.catmullRom)
}
}
.frame(maxHeight: paddingAmount)
.padding(.horizontal)
}
Hi Everyone, I would appreciate your help with the topic mentioned above. I'm seeking a solution for the issue I linked below.
https://discussions.apple.com/thread/255668660?sortBy=best
Apple Support said I could get a faster response. I've also submitted the issue to Apple Support, and they said it's currently with an Apple Engineer, but things are moving a bit slowly there. I'm writing the similar explanation I wrote on the discussion forum here as well. It's been months, and I hope we can get a result here:
**Here is the problem: **
I've noticed that the "CursorUIViewService" process in Activity Monitor is becoming 'not responding' and causing significant lag on my MacBook Air (M3), especially when typing and switching between upper and lower case letters. It appears this process also controls the blue caps-lock indicator, which stops working when the process is unresponsive. This issue seems to cause the lag, and currently, it is using about 170MB of RAM.
Additionally, the "com.apple.hiservices-xpcservice" process also becomes unresponsive , though it usually doesn't exceed 3.5MB of RAM. Actually, this process becomes 'not responding' much more frequently compared to the CursorUIViewService process. The possibility that it might be related to CursorUIViewService pushed me to research this issue as well. I can see that there have been complaints about this process for years, but it seems no solution is being produced.
By the way, I've tried everything. I did a clean install, ran diagnostics, performed first aid, and still encountered the problem.
Has anyone else experienced this issue or found a solution?
As an update, I would like to inform you that the "com.apple.hiservices-xpcservice" process is still experiencing not responding issues with macOS Sequoia (15.0). However, because "cursoruiviewservice" was causing problems less often on Sonoma, I can't say the issue is completely resolved just yet; I need to monitor the situation.
Thank you!
Hi all,
This post is from a blind user on Reddit looking for assistance. He created a ticket in the feedback app but was hoping there was another solution.
He is unable to post to these forums because VoiceOver doesn't allow him to set the tags appropriately. He asked that someone please post it here so he can get help.
Below is his post:
I’ve discovered another issue with VoiceOver in Xcode 16. We can’t add Plist keys to info.plist anymore. We can create a new row, but choosing a suggestion with VoiceOver is impossible.
My current workaround is to add a random key, save the file, and then open it as source code. I can edit the file in the code editor, but I lose great autocompletion and Plist handling. This is slowing me down, and I’m very unhappy with it. I’d appreciate it if you could share this post widely. Hopefully, a solution will be found. Thanks everyone!
(I can't link his original post here as it's not allowed.)
In short, is there any trick to getting Voiceover to work with plist files in Xcode 16?
I'm developing a macOS app that interacts with Microsoft Teams using the Accessibility API. I've noticed inconsistent behavior when querying UI elements, particularly for the mute button. My queries often fail, while system tools like VoiceOver can consistently access these elements (which are visible on the screen).
In some cases, it works well, but in others, the UI elements are not visible from my code. When I try Accessibility Inspector, it also initially fails to inspect. However, the Inspector seems to have some "magical" power that, when I run it or via AX audit, appears to refresh the AX tree, and then my code occasionally works as well.
Given that VoiceOver can consistently read the screen, I assume the issue is not with the Microsoft Teams app itself (assuming it's based on Electron/React). I am mentioning this, because when I interact with Zoom app, reading the mute status from the app's menu bar, its 100% working anytime.
What would you recommend I try or explore to improve reliability?
Can I refresh the apps' AX tree from my end from swift?
Is that a bug in AX API or even in Microsoft Teams?
(have ready example and demo video, but it does not let me upload here)
We are experiencing difficulties with keyboard navigation focus within a view contained inside a UIPageViewController. The intended keyboard navigation sequence does not function as expected.
Expected Behavior:
Pressing the Tab key once should move the focus to the UIPageViewController, allowing the use of the Up and Down arrow keys to navigate between pages.
Pressing the Tab key a second time should shift the focus outside the UIPageViewController
Pressing the Tab key a third time should move the focus back to the UIPageViewController.
Actual Behavior:
The focus does not shift as described above.
Have sent a sample Xcode project to Apple demonstrating the issue (unfortunately it doesn't allow me to attach the zipped project here for some reason).
STEPS TO REPRODUCE
Set a breakpoint at viewDidAppear (line 44, MyViewController)
Run the app, wait until it stops, and run the command in the lldb debugger
Command:
po UIFocusDebugger.checkFocusability(for: pager.viewControllers!.first!.view.subviews.first!)
Output:
The following issues were found that would prevent this item from being focusable:
- ISSUE: One or more ancestors have issues that may be preventing this item from being focusable. Details:
<_UIQueuingScrollView: 0x104826a00>:
- ISSUE: This view returns YES from -canBecomeFocused, which will prevent its subviews from being focusable.
<_UIPageViewControllerContentView: 0x103d07be0>:
- ISSUE: This view returns YES from -canBecomeFocused, which will prevent its subviews from being focusable.
One of my blind users reached out to me after they updated to iPadOS 18. I have a button that is used to mark/unmark a favorite location.
He said that he could still tell the favorite status via the label and hint, but VoiceOver was always saying that the switch button is off.
I'm able to recreate this on my iPad as well. The documentation for .isToggle is completely blank.
Basically with iPadOS 17 adding the .isToggle trait makes VoiceOver state that my button is a toggle.
With iPadOS 18 adding the .isToggle trait makes VoiceOver state that my button is a toggle AND try to state its current value. I don't know if this is intentional or a bug.
Button {
showFavActions()
} label: {
Image(systemName: SFSymbolShortcut.star.rawValue)
.symbolVariant(weatherData.currentlyFavIndex == nil ? .none : .fill)
}
.buttonStyle(.plain)
.accessibilityLabel(Text(weatherData.currentlyFavIndex == nil ? "Not a favorite location." : "Favorite location."))
.accessibilityHint(Text(weatherData.currentlyFavIndex == nil ? "Add to favorites." : "Remove from favorites."))
.accessibilityInputLabels(["Favorite"])
.accessibilityAddTraits(.isToggle) // iOS 17
SwiftUI Charts automatically groups accessibility elements on the graph (Double / Date for example) when there's a lot of data, which overrides the accessibilityLabel and value I set for each data point. This makes sense, but how do we modify the chart navigation accessibility readout when this grouping occurs?
Here's an example:
var body: some View {
let salesData: [(Date, Double)] = [
(Date().addingTimeInterval(-1 * 24 * 60 * 60), 1200),
(Date().addingTimeInterval(-2 * 24 * 60 * 60), 1500),
(Date().addingTimeInterval(-3 * 24 * 60 * 60), 1000),
(Date().addingTimeInterval(-4 * 24 * 60 * 60), 500),
(Date().addingTimeInterval(-5 * 24 * 60 * 60), 1500),
(Date().addingTimeInterval(-6 * 24 * 60 * 60), 1400),
(Date().addingTimeInterval(-7 * 24 * 60 * 60), 1300),
(Date().addingTimeInterval(-8 * 24 * 60 * 60), 1800),
(Date().addingTimeInterval(-9 * 24 * 60 * 60), 500),
(Date().addingTimeInterval(-10 * 24 * 60 * 60), 800),
(Date().addingTimeInterval(-11 * 24 * 60 * 60), 800),
(Date().addingTimeInterval(-12 * 24 * 60 * 60), 1000),
(Date().addingTimeInterval(-13 * 24 * 60 * 60), 1500),
(Date().addingTimeInterval(-14 * 24 * 60 * 60), 1500),
(Date().addingTimeInterval(-15 * 24 * 60 * 60), 900),
]
Chart {
ForEach(salesData, id: \.0) { date, sales in
LineMark(
x: .value("Foo", date),
y: .value("Bar", sales)
).accessibilityLabel("Foo: \(date.formatted(date: .abbreviated, time: .omitted)) Bar: \(sales.formatted(.currency(code: "USD")))")
}
}
.accessibilityElement(children: .contain)
}
}
I am wondering if there's a protocol, modifier.. or maybe something like UIAccessibilityContainerType.
Hello, I am trying to add an accessibility label and hint to a SwiftUI sheet's drag indicator but am not having any luck. Currently, VO reads 'sheet grabber, button, double tap to expand the sheet'. I'd really like VO to also include the current height of the sheet (similar to Apple Maps sheet). Does anyone by chance know how I can target the drag indicator/sheet grabber to do this? Thanks in advance.
Cannot turn on Guided Access for Vision OS 2.0 app in development
I tried open Guided Access mode by control panel or triple click on crown button. It all response nothing.
And after that other app cannot enter the Guided Access mode either.
When I switch off and on Guided Access in General -> Accessiblity. It work for other app. but not my developing app.
Hey guys, so I have a problem regarding the testIDs on my react native that is reproducible only on iOS DOM meaning that I set the ids individually on the elements on a page but the problem is that somehow the ids are concatenated between them and inherits all the ids under the parent. As you can see and imagine in the accessibility inspector, this is what my DOM looks like. I want to point out that the problem does not reproduce on Android, only on iOS. Can somebody help me with this and tell me if there is a way to disable this concatenation? What's relevant to tell you it's the fact that I need each element to have an unique ID for browserstack automated tests. But as you can see in the image an element contains all IDs concatenated for some reason. And here is the code for the page with this issue
So every time I put my phone in idle state the brightness automatically goes to minimum and it needs to be set after each screen on.
I’m using IOS 18 developer’s beta.
Hello,
I would like to make it possible for keyboard-only users to select the next and previous month buttons in a UIDatePicker, to prevent confusion due to having interactive images in my app which are not interactable with a keyboard.
The official documentation only says that the UIDatePicker component is accessible by default, and does not offer information on how to customize the keyboard navigation.
Is this possible?
Hi!
Is there a way to increase the color contrast of the calendar version of the SwiftUI DatePicker? Even with high contrast turned on in the general IOS settings, the contrast between the "Sun", "Mon", "Tue" etc and a plain white background is only 3.86:1, which is less than the WCAG AA recommendations of 4:5:1. The contrast with the text for non-selectable dates is even lower.
I tried a couple of different options - setting tint, foregroundColor and so on, but they don't change the text color.
Thanks in advance!
Hello!
I am working on an application with a chat feature. The chat is implemented using a UICollectionView. The content in our chat grows from the bottom and upwards, as is standard (like for instance the Messages app), with the most recent item being shown at the bottom.
We have implemented this using a "hack", flipping the collection view upside-down by using a transform, and flipping the content views of the cells upside down again. This works nicely; the only remaining problem is ensuring that elements are read in the correct order for users with VoiceOver enabled.
Standard behaviour with VoiceOver enabled for collection views is that swiping right moves focus to the next element, while swiping left moves focus to the previous element. Despite the collectionView being inverted (upside-down) swiping right with VoiceOver enabled moves focus to the element above, while swiping left moves focus to the element below. Is there any way to invert this behaviour?
I have looked at subclassing the collection view and overriding accessibilityIncrement and accessibilityDecrement, but it did not have any effect. It seems the standard collection view accessibility container implementation does not call these methods.
A lot of apps use undocumented App-prefs URLs to help users get to the iOS Settings screen needed to set up the app. In iOS 18, it seems like these all stopped working.
Here are the ones I currently use:
App-prefs:MESSAGES - broken in iOS 18
Used for SMS Protection.
App-prefs:Phone - broken in iOS 18
Used for Live Voicemail, Silence Unknown Callers, and SMS Reporting.
Some but not most paths have specific documented replacements. E.g. for Call Blocking & Identification you can use CXCallDirectoryManager.sharedInstance.openSettings() and this still works in iOS 18. But I don't see any other direct replacements.
Apple probably doesn't consider this a bug but I filed FB14378568 anyway.
I consider this an accessibility issue because many older, inexperienced, or users with disabilities have trouble finding the right Settings screen based on a textual description alone.
Accessibility ui server turned on right after iPhone turned on after iOS 18 beta 3. Due to this issue, volume is forced max. Cant change the volume.
Is there any approach or sample code available to use these APIs:
.chartScrollableAxes(.horizontal)
.chartScrollPosition(x: ...)
.chartScrollPosition(initialX: ...)
.chartScrollTargetBehavior(...)
.chartXVisibleDomain(length: ...)
Plus a gesture recognised or Pinch or Magnification to create a Swift Chart with an X axis that can be zoomed in or out with a pinch gesture? And when zoomed in at any level above 0, the chart can then be scrolled left to right along the X axis.
I've had success using .chartScrollableAxes with .chartXSelection in parallel, so would also like to keep the ability to select X values too.