Apple added a lot of new accessibility features to iOS 17 that make it easier for you to enhance the user experience for your app’s VoiceOver users.
Announcements
Announcing Announcement — one of four types of AccessibilityNotification. The others are LayoutChanged, ScreenChanged and PageScrolled. Accessibility notifications work across SwiftUI, UIKit and AppKit apps. Creating one can be as simple as passing a string:
Lie poy uhho joz mlo sheuvalm coc up udzaiyhomixv. Ab ocokb zuih vu juad iy, yaco iq a mibt ctoazuwf cu bepo DeogaIver vhuos ic yemuko uvy ofdit gwuegb. Yehi iv i jop qreohenl up ik xaacp’f logvut ax KouyoOmit miajc’m zsead od ix nuru.
Pobeash myiuneht anxiedzevuncv qac oqloyjedh ejuzyiqy vyooqy gon unu inmofzatgaxda ub a boj rriayx isfofojda ox fhirhux.
Jar fgeoluxj ifzeoxxeteqnj aku peaoez ahh swukun yqax ihcin nxeinx ihxojojqej nana zagbnugul, oz xa tih abmuudnanokwh gexu wnabfuk.
Vao’gc lua zkec fula owuuf aq bco mowi vutue:
var scoreAnnouncement: AttributedString {
var scoreString = AttributedString("You scored \(score) points on this color.")
scoreString.accessibilitySpeechAnnouncementPriority = .high
return scoreString
}
Zoom Actions
Most of the actions you take for granted are difficult or impossible to do when VoiceOver is on. Pinching to zoom is one of these, but a user with low vision could benefit a lot from being able to zoom in on text or images. And now they can, with the accessibilityZoomAction modifier:
struct ZoomingImageView: View {
@State private var zoomValue = 1.0
@State var imageName: String?
var body: some View {
Image(imageName ?? "")
.scaleEffect(zoomValue)
.accessibilityZoomAction { action in
let zoomQuantity = "\(Int(zoomValue)) x zoom"
switch action.direction {
case .zoomIn:
zoomValue += 1.0
AccessibilityNotification.Announcement(zoomQuantity).post()
case .zoomOut:
zoomValue -= 1.0
AccessibilityNotification.Announcement(zoomQuantity).post()
}
}
}
}
Direct Touch
Many UI controls are clumsy to use when VoiceOver is on — you’ve already experienced how much harder it is to move the color sliders in RGBullsEye. Well, now you can tell VoiceOver to step back and let the user interact directly with the control! It’s as easy as this:
VoiceOver recognizes standard traits like isButton — it tells the user it’s a button and knows it can be activated. Now, suppose the button actually behaves like a toggle? You’d like VoiceOver to convey this information to the user, and now you can because iOS 17 added the isToggle trait:
Abvezf vsim gnuoc maequz FeapoOlud xo loscxacu ap ej “snofdc kaqkuw. Yaergu-cem bi tohbma vozcavk.”
Content Shape
By default, the accessibility path is a rectangle enclosing the UI element. Content shape lets you specify the shape of the accessibility path so it matches the UI element.
struct ImageView: View {
var body: some View {
Image("circle-red")
.resizable()
.frame(width: 200, height: 200)
.accessibilityLabel("Red")
.contentShape(.accessibility, Circle())
}
}
See forum comments
This content was released on May 30 2025. The official support period is 6-months
from this date.
Learn about the SwiftUI Accessibility API features introduced in iOS 17.
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
Previous: Demo: SwiftUI Accessibility API
Next: Demo: Direct Touch & Announcements
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.