View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Código
  • SwiftUI Accessibility: Beyond the basics

    Go beyond the basics to deliver an exceptional accessibility experience. Learn how to use the new SwiftUI Previews in Xcode to explore the latest accessibility APIs and create fantastic, accessible apps for everyone. Find out how you can customize the automatic accessibility built into SwiftUI to make your own custom controls accessible. Explore best practices and identify where to improve your app's navigation experience using grouping and focus. And help supercharge navigation for VoiceOver users with the addition of rotors.

    Recursos

    • Accessibility
    • Creating accessible views
      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC23

    • Create accessible spatial experiences

    WWDC21

    • Add rich graphics to your SwiftUI app
    • Bring accessibility to charts in your app
    • Create accessible experiences for watchOS
    • Demystify SwiftUI
    • What's new in SwiftUI

    WWDC20

    • VoiceOver efficiency with custom rotors
  • Buscar neste vídeo...
    • 2:00 - Welcome to the Accessibility Preview

      struct ContentView: View {
          var body: some View {
              VStack {
                  Text("WWDC 2021")
                      .accessibilityAddTraits(.isHeader)
      
                  Text("SwiftUI Accessibility")
                  Text("Beyond the Basics")
      
                  Image(systemName: "checkmark.seal.fill")
              }
          }
      }
    • 4:30 - BudgetSlider

      struct BudgetSlider: View {
          @Binding var value: Double
          var label: String
      
          var body: some View {
              VStack(alignment: .leading) {
                  HStack {
                      Text(label)
                      Text(value.toDollars()).bold()
                  }
                  SliderShape(value: value)
                      .gesture(DragGesture().onChanged(handle))
              }
          }
      }
      
      struct SliderShape: View {
          var value: Double
      
          private struct BackgroundTrack: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .foregroundColor(Color(white: 0.2))
              }
          }
      
          private struct OverlayTrack: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .foregroundColor(Color(white: 0.95))
              }
          }
      
          private struct Knob: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .strokeBorder(Color(white: 0.7), lineWidth: 1)
                  .shadow(radius: 3)
              }
          }
      
          var body: some View {
              GeometryReader { geometry in
                  ZStack(alignment: .leading) {
                      BackgroundTrack(cornerRadius: geometry.size.height / 2)
      
                      OverlayTrack(cornerRadius: geometry.size.height / 2)
                          .frame(
                              width: max(geometry.size.height, geometry.size.width * CGFloat(value) + geometry.size.height / 2),
                              height: geometry.size.height)
      
                      Knob(cornerRadius: geometry.size.height / 2)
                          .frame(
                              width: geometry.size.height,
                              height: geometry.size.height)
                          .offset(x: max(0, geometry.size.width * CGFloat(value) - geometry.size.height / 2), y: 0)
                  }
              }
          }
      }
      
      extension Double {
          func toDollars() -> String {
              return "$\(Int(self))"
          }
      }
    • 5:15 - Slider

      struct StandardSlider: View {
          @Binding var value: Double
          var label: String
      
          var body: some View {
              Slider(value: $value, in: 0...1) {
                  Text(label) 
              }
          }
      }
    • 5:50 - Accessible BudgetSlider

      struct BudgetSlider: View {
          @Binding var value: Double
          var label: String
      
          var body: some View {
              VStack(alignment: .leading) {
                  HStack {
                      Text(label)
                      Text(value.toDollars()).bold()
                  }
                  SliderShape(value: value)
                      .gesture(DragGesture().onChanged(handle))
                      .accessibilityRepresentation {
                          Slider(value: $value, in: 0...1) {
                              Text(label)
                          }
                          .accessibilityValue(value.toDollars())
                      }
              }
          }
      }
      
      struct SliderShape: View {
          var value: Double
      
          private struct BackgroundTrack: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .foregroundColor(Color(white: 0.2))
              }
          }
      
          private struct OverlayTrack: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .foregroundColor(Color(white: 0.95))
              }
          }
      
          private struct Knob: View {
              var cornerRadius: CGFloat
              var body: some View {
                  RoundedRectangle(
                      cornerRadius: cornerRadius,
                      style: .continuous
                  )
                  .strokeBorder(Color(white: 0.7), lineWidth: 1)
                  .shadow(radius: 3)
              }
          }
      
          var body: some View {
              GeometryReader { geometry in
                  ZStack(alignment: .leading) {
                      BackgroundTrack(cornerRadius: geometry.size.height / 2)
      
                      OverlayTrack(cornerRadius: geometry.size.height / 2)
                          .frame(
                              width: max(geometry.size.height, geometry.size.width * CGFloat(value) + geometry.size.height / 2),
                              height: geometry.size.height)
      
                      Knob(cornerRadius: geometry.size.height / 2)
                          .frame(
                              width: geometry.size.height,
                              height: geometry.size.height)
                          .offset(x: max(0, geometry.size.width * CGFloat(value) - geometry.size.height / 2), y: 0)
                  }
              }
          }
      }
      
      extension Double {
          func toDollars() -> String {
              return "$\(Int(self))"
          }
      }
    • 7:05 - NavigationBarView

      struct NavigationBarView: View {
          var body: some View {
              HStack {
                  Text("Wallet Pal")
                      .font(.largeTitle)
                      .bold()
      
                  Spacer()
      
                  Button("Edit Budgets", action: { ... })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "slider.vertical.3"))
              }
          }
      }
      
      struct SymbolButtonStyle: ButtonStyle {
          let systemName: String
      
          func makeBody(configuration: Configuration) -> some View {
      				Image(systemName: systemName)
                  .accessibilityRepresentation { configuration.label }
          }
      }
    • 9:40 - BudgetHistoryGraph

      struct Budget: Identifiable {
          var month: String
          var amount: Double
      
          var id: String { month }
      }
      
      struct BudgetHistoryGraph: View {
          var budgets: [Budget]
      
          var body: some View {
              GeometryReader { proxy in
                  VStack {
                      Canvas { ctx, size in
                          let inset: CGFloat = 25
                          let insetSize = CGSize(width: size.width, height: size.height - inset * 2)
                          let width = insetSize.width / CGFloat(budgets.count)
                          let max = budgets.map(\.amount).max() ?? 0
                          for n in budgets.indices {
                              let x = width * CGFloat(n)
                              let height = (CGFloat(budgets[n].amount) / CGFloat(max)) * insetSize.height
                              let y = insetSize.height - height
                              let p = Path(
                                  roundedRect: CGRect(
                                      x: x + 2.5,
                                      y: y + inset,
                                      width: width - 5,
                                      height: height),
                                  cornerRadius: 4)
                              ctx.fill(p, with: .color(Color.green))
      
                              ctx.draw(Text(budgets[n].amount.toDollars()), at: CGPoint(x: x + width / 2, y: y + inset / 2))
      
                              ctx.draw(Text(budgets[n].month), at: CGPoint(x: x + width / 2, y: y + height + 1.5*inset))
                          }
                      }
                      .accessibilityLabel("Budget History Graph")
                      .accessibilityChildren {
                          HStack {
                              ForEach(budgets) { budget in
                                  Rectangle()
                                      .accessibilityLabel(budget.month)
                                      .accessibilityValue(budget.amount.toDollars())
      
                              }
                          }
                      }
      
                  }
              }
              .padding()
              .background(
                  RoundedRectangle(cornerRadius: 16)
                      .foregroundColor(Color(white: 0.9)))
              .padding(.horizontal)
          }
      }
    • 12:30 - Composition

      // See CompositionExample.swift in the referenced sample project
    • 13:50 - FriendCellView

      struct User: Identifiable {
          var id: Int
          var name: String
          var photo: String
      }
      
      struct FriendCellView: View {
          var user: User
      
          var body: some View {
              ZStack(alignment: .topLeading) {
                  VStack(alignment: .center) {
                      Image(user.photo)
                      Text(user.name)
                  }
      
                  Button("Send Challenge", action: { /* ... */ })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "gamecontroller.fill"))
              }
          }
      }
      
      struct SymbolButtonStyle: ButtonStyle {
          let systemName: String
      
          func makeBody(configuration: Configuration) -> some View {
      				Image(systemName: systemName)
                  .accessibilityRepresentation { configuration.label }
          }
      }
    • 14:50 - FriendsView

      struct User: Identifiable {
          var id: Int
          var name: String
          var photo: String
      }
      
      struct FriendCellView: View {
          var user: User
      
          var body: some View {
              ZStack(alignment: .topLeading) {
                  VStack(alignment: .center) {
                      Image(user.photo)
                      Text(user.name)
                  }
      
                  Button("Send Challenge", action: { /* ... */ })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "gamecontroller.fill"))
              }
          }
      }
            
      struct FriendsView: View {
          var users: [User]
      
          var body: some View {
              ScrollView(.horizontal, showsIndicators: false) {
                  HStack {
                      ForEach(users) { user in
                          FriendCellView(user: user)
                              .onTapGesture { /* ... */ }
                      }
      
                      AddFriendButton()
      
                      Spacer()
                  }
              }
          }
      }
        
      struct AddFriendButton: View {
          var body: some View {
              Button(action: { /* ... */ }) {
                  Circle()
                      .foregroundColor(Color(white: 0.9))
                      .frame(width: 50, height: 50)
                      .overlay(
                          Image(systemName: "plus")
                              .resizable()
                              .foregroundColor(Color(white: 0.5))
                              .padding(15)
                      )
              }
              .buttonStyle(PlainButtonStyle())
          }
      }
      
      struct SymbolButtonStyle: ButtonStyle {
          let systemName: String
      
          func makeBody(configuration: Configuration) -> some View {
      				Image(systemName: systemName)
                  .accessibilityRepresentation { configuration.label }
          }
      }
    • 15:10 - FriendsView with Containers

      struct User: Identifiable {
          var id: Int
          var name: String
          var photo: String
      }
      
      struct FriendCellView: View {
          var user: User
      
          var body: some View {
              ZStack(alignment: .topLeading) {
                  VStack(alignment: .center) {
                      Image(user.photo)
                      Text(user.name)
                  }
      
                  Button("Send Challenge", action: { /* ... */ })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "gamecontroller.fill"))
              }
          }
      }
            
      struct FriendsView: View {
          var users: [User]
      
          var body: some View {
              ScrollView(.horizontal, showsIndicators: false) {
                  HStack {
                      ForEach(users) { user in
                          FriendCellView(user: user)
                               .accessibilityElement(children: .contain)
                              .onTapGesture { /* ... */ }
                      }
      
                      AddFriendButton()
      
                      Spacer()
                  }
              }
          }
      }
        
      struct AddFriendButton: View {
          var body: some View {
              Button(action: { /* ... */ }) {
                  Circle()
                      .foregroundColor(Color(white: 0.9))
                      .frame(width: 50, height: 50)
                      .overlay(
                          Image(systemName: "plus")
                              .resizable()
                              .foregroundColor(Color(white: 0.5))
                              .padding(15)
                      )
              }
              .buttonStyle(PlainButtonStyle())
          }
      }
      
      struct SymbolButtonStyle: ButtonStyle {
          let systemName: String
      
          func makeBody(configuration: Configuration) -> some View {
      				Image(systemName: systemName)
                  .accessibilityRepresentation { configuration.label }
          }
      }
    • 16:20 - FriendCellView Sort Priority

      struct User: Identifiable {
          var id: Int
          var name: String
          var photo: String
      }
      
      struct FriendCellView: View {
          var user: User
      
          var body: some View {
              ZStack(alignment: .topLeading) {
                  VStack(alignment: .center) {
                      Image(user.photo)
                      Text(user.name)
                  }
      
                  Button("Send Challenge", action: { /* ... */ })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "gamecontroller.fill"))
                      .accessibilitySortPriority(-1)
              }
          }
      }
    • 16:55 - FriendsView with .combine

      struct User: Identifiable {
          var id: Int
          var name: String
          var photo: String
      }
      
      struct FriendCellView: View {
          var user: User
      
          var body: some View {
              ZStack(alignment: .topLeading) {
                  VStack(alignment: .center) {
                      Image(user.photo)
                      Text(user.name)
                  }
      
                  Button("Send Challenge", action: { /* ... */ })
                      .buttonStyle(
                          SymbolButtonStyle(
                              systemName: "gamecontroller.fill"))
              }
          }
      }
            
      struct FriendsView: View {
          var users: [User]
      
          var body: some View {
              ScrollView(.horizontal, showsIndicators: false) {
                  HStack {
                      ForEach(users) { user in
                          FriendCellView(user: user)
                              .accessibilityElement(children: .combine)
                              .onTapGesture { /* ... */ }
                      }
      
                      AddFriendButton()
      
                      Spacer()
                  }
              }
          }
      }
        
      struct AddFriendButton: View {
          var body: some View {
              Button(action: { /* ... */ }) {
                  Circle()
                      .foregroundColor(Color(white: 0.9))
                      .frame(width: 50, height: 50)
                      .overlay(
                          Image(systemName: "plus")
                              .resizable()
                              .foregroundColor(Color(white: 0.5))
                              .padding(15)
                      )
              }
              .buttonStyle(PlainButtonStyle())
          }
      }
      
      struct SymbolButtonStyle: ButtonStyle {
          let systemName: String
      
          func makeBody(configuration: Configuration) -> some View {
      				Image(systemName: systemName)
                  .accessibilityRepresentation { configuration.label }
          }
      }
    • 20:30 - AlertsView Implicit Rotor

      struct Alert: Identifiable {
          var id: Int
          var isUnread: Bool
          var isFlagged: Bool
          var subject: String
          var content: String
      }
      
      struct AlertsView: View {
          var alerts: [Alert]
      
          var body: some View {
              VStack {
                  ForEach(alerts) { alert in
                      AlertCellView(alert: alert)
                          .accessibilityElement(children: .combine)
                  }
              }
              .accessibilityElement(children: .contain)
              .accessibilityRotor("Warnings") {
                  ForEach(alerts) { alert in
                      if alert.isWarning {
                          AccessibilityRotorEntry(alert.title, id: alert.id)
                      }
                  }
              }
          }
      }
      
      struct AlertCell: View {
          var alert: Alert
      
          var body: some View {
              VStack(alignment: .leading) {
                  HStack {
                      if alert.isUnread {
                          Circle()
                              .foregroundColor(.blue)
                              .frame(width: 10, height: 10)
                      }
                      if alert.isFlagged {
                          Image(systemName: "exclamationmark.triangle.fill")
                              .foregroundColor(.orange)
                              .frame(width: 10, height: 10)
                      }
                      Text(alert.subject)
                          .font(.headline)
                          .fontWeight(.semibold)
                      Spacer()
                      Text("04/30/21")
                          .font(.subheadline)
                          .foregroundColor(.secondary)
                  }
                  Text(alert.content)
                      .lineLimit(3)
              }
              .padding(10)
              .background(
                  RoundedRectangle(cornerRadius: 8)
                      .foregroundColor(Color(white: 0.9))
              )
          }
      }
    • 21:50 - AlertsView Explicit Rotor

      struct Alert: Identifiable {
          var id: Int
          var isUnread: Bool
          var isFlagged: Bool
          var subject: String
          var content: String
      }
      
      struct AlertsView: View {
          var alerts: [Alert]
          @Namespace var namespace
      
          var body: some View {
              VStack {
                  ForEach(alerts) { alert in
                      VStack {
                          AlertCellView(alert: alert)
                              .accessibilityElement(children: .combine)
                              .accessibilityRotorEntry(id: alert.id, in: namespace)
                          AlertActionsView(alert: alert)
                      }
                  }
              }
              .accessibilityElement(children: .contain)
              .accessibilityRotor("Warnings") {
                  ForEach(alerts) { alert in
                      if alert.isWarning {
                          AccessibilityRotorEntry(alert.title, id: alert.id, in: namespace)
                      }
                  }
              }
          }
      }
      
      struct AlertCell: View {
          var alert: Alert
      
          var body: some View {
              VStack(alignment: .leading) {
                  HStack {
                      if alert.isUnread {
                          Circle()
                              .foregroundColor(.blue)
                              .frame(width: 10, height: 10)
                      }
                      if alert.isFlagged {
                          Image(systemName: "exclamationmark.triangle.fill")
                              .foregroundColor(.orange)
                              .frame(width: 10, height: 10)
                      }
                      Text(alert.subject)
                          .font(.headline)
                          .fontWeight(.semibold)
                      Spacer()
                      Text("04/30/21")
                          .font(.subheadline)
                          .foregroundColor(.secondary)
                  }
                  Text(alert.content)
                      .lineLimit(3)
              }
              .padding(10)
              .background(
                  RoundedRectangle(cornerRadius: 8)
                      .foregroundColor(Color(white: 0.9))
              )
          }
      }
    • 22:20 - TextEditor Rotors

      struct ContentView: View {
          @State var note: Note
      
          var body: some View {
              TextEditor($text.content)
                  .accessibilityRotor("Email Addresses", textRanges: note.addressRanges)
                  .accessibilityRotor("Links", textRanges: note.linkRanges)
                  .accessibilityRotor("Phone Numbers", textRanges: note.phoneNumberRanges)
          }
      }
    • 24:45 - AlertNotificationView

      struct Notification: Equatable {
          enum Priority {
              case low, high
          }
          var content: String
          var priority: Priority
      }
      
      struct AlertNotificationView<Content: View>: View {
          @ViewBuilder var content: Content
          @Binding var notification: Notification?
          @AccessibilityFocusState var isNotificationFocused: Bool
      
          var body: some View {
              ZStack(alignment: .top) {
                  content
      
                  if let notification = $notification {
                      NotificationBanner(notification: notification)
                          .accessibilityFocused($isNotificationFocused)
                  }
              }
              .onChange(of: notification) { notification in
                  if notification?.priority == .high {
                      isNotificationFocused = true
                  } else {
                      postAccessibilityNotification()
                  }
              }
          }
      
          func postAccessibilityNotification() {
              guard let announcement = notification?.content else {
                  return
              }
              #if os(macOS)
              NSAccessibility.post(
                  element: NSApp.accessibilityWindow(),
                  notification: .announcementRequested,
                  userInfo: [.announcement: announcement])
              #else
              UIAccessibility.post(notification: .announcement, argument: announcement)
              #endif
          }
      }
      
      struct NotificationBanner: View {
          @Binding var notification: Notification?
          @State var timer: Timer?
          @AccessibilityFocusState var isNotificationFocused: Bool
      
          var body: some View {
              if let notification = notification {
                  Text(notification.content)
                      .accessibilityFocused($isNotificationFocused)
                      .onAppear { startTimer() }
                      .onDisappear { stopTimer() }
              } else {
                  EmptyView()
              }
          }
      
          func startTimer() {
              timer = Timer.scheduledTimer(
                  withTimeInterval: 3,
                  repeats: true) { _ in
                  if !isNotificationFocused {
                      notification = nil
                  }
              }
          }
      
          func stopTimer() {
              timer?.invalidate()
          }
      }

Developer Footer

  • Vídeos
  • WWDC21
  • SwiftUI Accessibility: Beyond the basics
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines