# iOS-Accessibility-Interviewfragen 2026: VoiceOver und Dynamic Type > Vorbereitung auf iOS-Interviews mit zentralen Accessibility-Fragen: VoiceOver, Dynamic Type, semantische Traits und Audits. - Published: 2026-03-12 - Updated: 2026-05-01 - Author: SharpSkill - Tags: ios, accessibility, voiceover, dynamic-type, swift - Reading time: 14 min --- Barrierefreiheit ist zu einer entscheidenden Fähigkeit in der iOS-Entwicklung geworden. Recruiter prüfen mittlerweile systematisch das Beherrschen von VoiceOver, Dynamic Type und Accessibility-APIs. Die folgenden Fragen decken die wesentlichen Konzepte ab, um in technischen Interviews erfolgreich zu sein. > **Warum Barrierefreiheit im Interview zählt** > > Über eine Milliarde Menschen leben mit einer Behinderung. Apple setzt strenge Accessibility-Standards durch, und viele Unternehmen veröffentlichen keine unzugänglichen Apps. Diese Kompetenz hebt Senior-Kandidaten von der Masse ab. ## Grundlagen der iOS-Accessibility ### 1. Welche sind die wichtigsten Accessibility-Werkzeuge unter iOS? iOS bietet ein umfassendes Ökosystem von Accessibility-Werkzeugen, die unterschiedliche Arten von Behinderungen adressieren. VoiceOver ermöglicht Bildschirmausgabe für blinde und sehbehinderte Nutzer. Dynamic Type passt die Textgröße an. Switch Control unterstützt externe Schalter. Voice Control bietet vollständige Sprachsteuerung. ```swift // AccessibilityTools.swift // Check if VoiceOver is running if UIAccessibility.isVoiceOverRunning { // Adapt the interface for VoiceOver showSimplifiedInterface() } // Check if Reduce Motion is enabled if UIAccessibility.isReduceMotionEnabled { // Disable complex animations animationDuration = 0 } // Check if Bold Text is enabled if UIAccessibility.isBoldTextEnabled { // Use heavier fonts applyBoldFonts() } // Observe settings changes NotificationCenter.default.addObserver( forName: UIAccessibility.voiceOverStatusDidChangeNotification, object: nil, queue: .main ) { _ in // React to the change updateAccessibilityLayout() } ``` Diese APIs erlauben es, die Oberfläche dynamisch an die Nutzerpräferenzen und aktiven Hilfstechnologien anzupassen. ### 2. Wie funktioniert VoiceOver technisch? VoiceOver durchläuft die Oberfläche und identifiziert die zugänglichen Elemente. Jedes Element stellt Eigenschaften wie Label, Value, Traits und Aktionen bereit. Der Screenreader synthetisiert diese Informationen vokal, während der Nutzer per Geste navigiert. ```swift // VoiceOverBasics.swift // In UIKit: configure an accessible element class CustomButton: UIButton { override var accessibilityLabel: String? { get { "Validation button" } // What VoiceOver reads set { } } override var accessibilityHint: String? { get { "Double-tap to confirm the order" } // Possible action set { } } override var accessibilityTraits: UIAccessibilityTraits { get { .button } // Element type set { } } override var isAccessibilityElement: Bool { get { true } // Element focusable by VoiceOver set { } } } // In SwiftUI: equivalent with modifiers struct ValidateButton: View { var body: some View { Button("Validate") { confirmOrder() } .accessibilityLabel("Validation button") .accessibilityHint("Double-tap to confirm the order") } } ``` Die Accessibility-Hierarchie kann von der visuellen Hierarchie abweichen, was logische Navigation auch bei komplexen Layouts erlaubt. ### 3. Was ist der Unterschied zwischen accessibilityLabel und accessibilityValue? Das `accessibilityLabel` identifiziert das Element dauerhaft, während `accessibilityValue` seinen aktuellen, veränderlichen Zustand abbildet. Diese Unterscheidung ist entscheidend für dynamische Steuerelemente wie Slider oder Switches. ```swift // LabelVsValue.swift // Example with a volume slider class VolumeSlider: UISlider { override var accessibilityLabel: String? { get { "Volume" } // Fixed element identity set { } } override var accessibilityValue: String? { get { "\(Int(value * 100)) percent" } // Current state that changes set { } } } // VoiceOver reads: "Volume, 75 percent" // In SwiftUI with a Toggle struct NotificationToggle: View { @Binding var isEnabled: Bool var body: some View { Toggle(isOn: $isEnabled) { Text("Notifications") } .accessibilityLabel("Push notifications") // accessibilityValue is automatic for Toggle: "on" or "off" } } // For a custom stepper struct QuantityStepper: View { @State private var quantity = 1 var body: some View { Stepper("Quantity", value: $quantity, in: 1...99) .accessibilityLabel("Item quantity") .accessibilityValue("\(quantity) item\(quantity > 1 ? "s" : "")") } } ``` VoiceOver gibt stets das Label gefolgt vom Value aus, sodass Nutzer sowohl das Element als auch dessen aktuellen Zustand erfassen. ### 4. Erkläre accessibilityTraits und ihre Bedeutung Traits informieren VoiceOver über Typ und Verhalten eines Elements. Sie bestimmen, wie das Element angesagt wird und welche Aktionen verfügbar sind. Ein Button ohne den Trait `.button` wird nicht als solcher angekündigt. ```swift // AccessibilityTraits.swift // Common traits in UIKit class CustomCell: UITableViewCell { override var accessibilityTraits: UIAccessibilityTraits { get { var traits: UIAccessibilityTraits = [] // Element type traits.insert(.button) // Interactive element // Current state if isSelected { traits.insert(.selected) // Currently selected } // Special characteristics if !isEnabled { traits.insert(.notEnabled) // Disabled } return traits } set { } } } // Available traits // .button - Clickable element // .link - Hyperlink // .header - Section header // .image - Image // .selected - Selected state // .notEnabled - Disabled // .adjustable - Adjustable value (slider) // .staticText - Non-interactive text // .searchField - Search field // .playsSound - Plays a sound // .startsMediaSession - Starts media playback // In SwiftUI struct SectionHeader: View { let title: String var body: some View { Text(title) .font(.headline) .accessibilityAddTraits(.isHeader) // Announced as header } } struct SelectableRow: View { let isSelected: Bool var body: some View { HStack { Text("Option") if isSelected { Image(systemName: "checkmark") } } .accessibilityElement(children: .combine) .accessibilityAddTraits(isSelected ? .isSelected : []) } } ``` Traits sorgen dafür, dass Hilfstechnologien eine konsistente und vorhersehbare Erfahrung bieten. ## Dynamic Type und adaptive Schriftgrößen ### 5. Wie wird Dynamic Type korrekt implementiert? Dynamic Type erlaubt es Nutzern, die Systemschriftgröße anzupassen. Eine korrekte Implementierung verwendet semantische Textstile und flexible Constraints, damit sich die Oberfläche automatisch anpasst. ```swift // DynamicType.swift // In UIKit: use preferred text styles class ArticleCell: UITableViewCell { let titleLabel = UILabel() let bodyLabel = UILabel() func configure() { // Use semantic text styles titleLabel.font = UIFont.preferredFont(forTextStyle: .headline) bodyLabel.font = UIFont.preferredFont(forTextStyle: .body) // CRUCIAL: enable automatic adjustment titleLabel.adjustsFontForContentSizeCategory = true bodyLabel.adjustsFontForContentSizeCategory = true // Allow multiline for large sizes titleLabel.numberOfLines = 0 bodyLabel.numberOfLines = 0 } } // In SwiftUI: it's automatic with styles struct ArticleView: View { var body: some View { VStack(alignment: .leading) { Text("Article Title") .font(.headline) // Adapts automatically Text("Article content...") .font(.body) } } } // Custom font with Dynamic Type extension UIFont { static func customFont( size: CGFloat, style: TextStyle ) -> UIFont { let customFont = UIFont(name: "CustomFont-Regular", size: size)! // Adapt to current size category return UIFontMetrics(forTextStyle: style) .scaledFont(for: customFont) } } ``` Ohne `adjustsFontForContentSizeCategory` behalten Labels ihre Ausgangsgröße, selbst wenn der Nutzer seine Präferenzen ändert. ### 6. Wie geht man mit extremen Accessibility-Größen um? Die Accessibility-Größen (AX1 bis AX5) können den Text bis aufs Dreifache vergrößern. Die Oberfläche muss mit alternativen Layouts reagieren: vertikale statt horizontaler Anordnung, Ausblenden dekorativer Elemente und Anpassung der Abstände. ```swift // LargeContentSize.swift // Detect accessibility sizes struct AdaptiveLayout: View { @Environment(\.dynamicTypeSize) var dynamicTypeSize var body: some View { // Different layout for large sizes if dynamicTypeSize.isAccessibilitySize { // Vertical layout for large sizes VStack(alignment: .leading, spacing: 12) { iconAndTitle actionButtons } } else { // Standard horizontal layout HStack { iconAndTitle Spacer() actionButtons } } } var iconAndTitle: some View { HStack { Image(systemName: "bell.fill") .accessibilityHidden(true) // Decorative, ignore Text("Notifications") } } var actionButtons: some View { HStack(spacing: 16) { Button("Enable") { } Button("Settings") { } } } } // In UIKit: observe changes class AdaptiveViewController: UIViewController { override func traitCollectionDidChange( _ previousTraitCollection: UITraitCollection? ) { super.traitCollectionDidChange(previousTraitCollection) // Check if size category changed if traitCollection.preferredContentSizeCategory != previousTraitCollection?.preferredContentSizeCategory { updateLayoutForContentSize() } } func updateLayoutForContentSize() { let category = traitCollection.preferredContentSizeCategory if category.isAccessibilityCategory { // Enable accessible layout stackView.axis = .vertical decorativeView.isHidden = true } else { // Standard layout stackView.axis = .horizontal decorativeView.isHidden = false } } } ``` Die Accessibility-Kategorien beginnen bei `.accessibilityMedium` (AX1). Das Design muss diese Fälle von Anfang an berücksichtigen. ### 7. Wie macht man Bilder zugänglich? Bilder erfordern eine unterschiedliche Behandlung je nach Funktion: informative Bilder benötigen Beschreibungen, dekorative sollen ignoriert werden, interaktive verlangen aktionsbezogene Labels. ```swift // AccessibleImages.swift // Informative image: describe the content struct ProductImage: View { let product: Product var body: some View { AsyncImage(url: product.imageURL) { image in image .resizable() .accessibilityLabel(product.imageDescription) // "Product photo: iPhone 15 Pro, titanium color" } placeholder: { ProgressView() .accessibilityLabel("Loading image") } } } // Decorative image: hide from VoiceOver struct DecorationView: View { var body: some View { Image(systemName: "sparkles") .accessibilityHidden(true) // Ignored by VoiceOver } } // Image button: describe the action, not the image struct FavoriteButton: View { @Binding var isFavorite: Bool var body: some View { Button { isFavorite.toggle() } label: { Image(systemName: isFavorite ? "heart.fill" : "heart") } // Don't describe the icon, describe the action .accessibilityLabel(isFavorite ? "Remove from favorites" : "Add to favorites") } } // In UIKit class ProductImageView: UIImageView { override var isAccessibilityElement: Bool { get { true } set { } } func configure(with product: Product) { image = product.image accessibilityLabel = "Photo: \(product.name), \(product.color)" } } // Image with embedded text (infographic) class InfographicView: UIImageView { override var accessibilityLabel: String? { get { // Transcribe the textual content of the infographic """ Statistics infographic 2026. Growth: 45%. Active users: 2.3 million. Satisfaction: 4.8 out of 5. """ } set { } } } ``` Ein schlecht beschriebenes oder ein nicht ausgeblendetes dekoratives Bild verschlechtert die VoiceOver-Erfahrung deutlich. ## Gruppierung und fortgeschrittene Navigation ### 8. Wie gruppiert man Elemente für VoiceOver? Die Gruppierung fasst mehrere visuelle Elemente zu einem zugänglichen zusammen. Das beschleunigt die Navigation und liefert den vollständigen Kontext in einer einzigen Ansage. ```swift // AccessibilityGrouping.swift // In SwiftUI: combine children struct ProductCard: View { let product: Product var body: some View { VStack(alignment: .leading) { Text(product.name) .font(.headline) Text(product.price) .font(.subheadline) HStack { Image(systemName: "star.fill") Text(product.rating) } } // Combines all text into a single element .accessibilityElement(children: .combine) // VoiceOver reads: "iPhone 15 Pro, $1199, 4.8 stars" } } // In SwiftUI: ignore children and define manually struct OrderSummary: View { let order: Order var body: some View { HStack { Image(systemName: "bag") VStack(alignment: .leading) { Text(order.itemCount) Text(order.total) } Image(systemName: "chevron.right") } // Ignore children hierarchy .accessibilityElement(children: .ignore) // Define custom label .accessibilityLabel("Order of \(order.itemCount) items for \(order.total)") .accessibilityHint("Double-tap to view details") .accessibilityAddTraits(.isButton) } } // In UIKit: accessible container class ProductCardView: UIView { let nameLabel = UILabel() let priceLabel = UILabel() let ratingLabel = UILabel() override var isAccessibilityElement: Bool { get { true } // The container is the accessible element set { } } override var accessibilityLabel: String? { get { // Combine information "\(nameLabel.text ?? ""), \(priceLabel.text ?? ""), \(ratingLabel.text ?? "")" } set { } } } ``` Ohne Gruppierung hält VoiceOver bei jedem einzelnen Text an, was die Navigation deutlich verlangsamt. ### 9. Wie implementiert man benutzerdefinierte Accessibility-Aktionen? Benutzerdefinierte Aktionen ergänzen zugängliche Funktionen, ohne die visuelle Oberfläche zu überladen. VoiceOver-Nutzer rufen sie per vertikalem Swipe auf. ```swift // CustomAccessibilityActions.swift // In SwiftUI: custom actions struct EmailRow: View { let email: Email let onArchive: () -> Void let onDelete: () -> Void let onFlag: () -> Void var body: some View { HStack { VStack(alignment: .leading) { Text(email.sender) .font(.headline) Text(email.subject) .font(.subheadline) } Spacer() if email.isFlagged { Image(systemName: "flag.fill") } } .accessibilityElement(children: .combine) .accessibilityLabel("\(email.sender), \(email.subject)") // Actions accessible via vertical swipe .accessibilityAction(named: "Archive") { onArchive() } .accessibilityAction(named: "Delete") { onDelete() } .accessibilityAction(named: email.isFlagged ? "Remove flag" : "Flag") { onFlag() } } } // In UIKit: override accessibilityCustomActions class EmailCell: UITableViewCell { var email: Email! var onArchive: (() -> Void)? var onDelete: (() -> Void)? override var accessibilityCustomActions: [UIAccessibilityCustomAction]? { get { [ UIAccessibilityCustomAction( name: "Archive", target: self, selector: #selector(archiveAction) ), UIAccessibilityCustomAction( name: "Delete", target: self, selector: #selector(deleteAction) ) ] } set { } } @objc private func archiveAction() -> Bool { onArchive?() return true // true = action succeeded } @objc private func deleteAction() -> Bool { onDelete?() return true } } ``` Benutzerdefinierte Aktionen ersetzen vorteilhaft die schwer auffindbaren Swipe-Gesten unter VoiceOver. ### 10. Wie steuert man den VoiceOver-Fokus programmatisch? Die Fokussteuerung ist nach Änderungen an der Oberfläche essenziell: Modal erscheint, Inhalt lädt, Navigation. Der Fokus muss Nutzer zur relevanten Information führen. ```swift // AccessibilityFocus.swift // In SwiftUI with @AccessibilityFocusState (iOS 15+) struct SearchView: View { @State private var searchText = "" @State private var results: [Result] = [] @AccessibilityFocusState private var focusedResult: Result? var body: some View { VStack { TextField("Search", text: $searchText) .onSubmit { performSearch() } List(results) { result in ResultRow(result: result) .accessibilityFocused($focusedResult, equals: result) } } } func performSearch() { Task { results = await api.search(searchText) // Move focus to first result if let first = results.first { focusedResult = first } } } } // In UIKit: post a notification class ModalViewController: UIViewController { @IBOutlet weak var titleLabel: UILabel! override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Announce and move focus UIAccessibility.post( notification: .screenChanged, // New screen argument: titleLabel // Element to focus ) } func showError(_ message: String) { errorLabel.text = message errorLabel.isHidden = false // Announce layout change UIAccessibility.post( notification: .layoutChanged, // Change in current screen argument: errorLabel ) } func showLoadingComplete() { // Announce without moving focus UIAccessibility.post( notification: .announcement, argument: "Loading complete" ) } } ``` Die Notifications `.screenChanged` und `.layoutChanged` informieren VoiceOver über bedeutende Änderungen der Oberfläche. ## Anpassbare Elemente und komplexe Steuerungen ### 11. Wie macht man einen benutzerdefinierten Slider zugänglich? Ein benutzerdefinierter Slider muss den Trait `.adjustable` implementieren und auf Increment-/Decrement-Gesten reagieren. VoiceOver verwendet vertikale Swipes, um den Wert zu ändern. ```swift // AccessibleSlider.swift // In SwiftUI: Slider is accessible by default struct VolumeControl: View { @Binding var volume: Double var body: some View { Slider(value: $volume, in: 0...100, step: 5) .accessibilityLabel("Volume") .accessibilityValue("\(Int(volume)) percent") } } // Custom accessible slider struct CustomRatingSlider: View { @Binding var rating: Int var body: some View { HStack { ForEach(1...5, id: \.self) { star in Image(systemName: star <= rating ? "star.fill" : "star") .onTapGesture { rating = star } } } .accessibilityElement(children: .ignore) .accessibilityLabel("Rating") .accessibilityValue("\(rating) star\(rating > 1 ? "s" : "") out of 5") .accessibilityAdjustableAction { direction in switch direction { case .increment: rating = min(5, rating + 1) case .decrement: rating = max(1, rating - 1) @unknown default: break } } } } // In UIKit: adjustable trait class StarRatingView: UIView { var rating: Int = 3 { didSet { updateStars() // Announce the new value UIAccessibility.post( notification: .announcement, argument: accessibilityValue ) } } override var accessibilityTraits: UIAccessibilityTraits { get { .adjustable } // Enables adjustment gestures set { } } override var accessibilityLabel: String? { get { "Rating" } set { } } override var accessibilityValue: String? { get { "\(rating) stars out of 5" } set { } } // Called on swipe up override func accessibilityIncrement() { rating = min(5, rating + 1) } // Called on swipe down override func accessibilityDecrement() { rating = max(1, rating - 1) } } ``` Ohne den Trait `.adjustable` müsste der Nutzer jeden Stern einzeln antippen. ### 12. Wie erstellt man ein zugängliches Karussell? Karussells stellen Accessibility-Herausforderungen: nicht-lineare Navigation, außerhalb des Bildschirms liegende Inhalte und mehrere Zustände. Die Lösung kombiniert den Trait `.adjustable` mit kontextuellen Ansagen. ```swift // AccessibleCarousel.swift struct ImageCarousel: View { let images: [CarouselImage] @State private var currentIndex = 0 var body: some View { TabView(selection: $currentIndex) { ForEach(images.indices, id: \.self) { index in CarouselItem(image: images[index]) .tag(index) } } .tabViewStyle(.page) .accessibilityElement(children: .contain) .accessibilityLabel("Image carousel") .accessibilityValue("Image \(currentIndex + 1) of \(images.count)") .accessibilityHint("Swipe to change image") .accessibilityAdjustableAction { direction in withAnimation { switch direction { case .increment: currentIndex = min(images.count - 1, currentIndex + 1) case .decrement: currentIndex = max(0, currentIndex - 1) @unknown default: break } } } } } // In UIKit with UIPageViewController class CarouselAccessibilityContainer: UIView { var currentPage = 0 var totalPages = 5 override var isAccessibilityElement: Bool { get { true } set { } } override var accessibilityTraits: UIAccessibilityTraits { get { .adjustable } set { } } override var accessibilityLabel: String? { get { "Promotional carousel" } set { } } override var accessibilityValue: String? { get { "Page \(currentPage + 1) of \(totalPages)" } set { } } override func accessibilityIncrement() { guard currentPage < totalPages - 1 else { return } currentPage += 1 delegate?.scrollToPage(currentPage) } override func accessibilityDecrement() { guard currentPage > 0 else { return } currentPage -= 1 delegate?.scrollToPage(currentPage) } } ``` Dieser Ansatz ermöglicht das Navigieren im Karussell, ohne auf Standard-Swipe-Gesten angewiesen zu sein. ### 13. Wie geht man mit der Accessibility von Formularen um? Zugängliche Formulare verknüpfen jedes Feld mit seinem Label, weisen Fehler klar aus und ermöglichen flüssige Navigation zwischen den Feldern. ```swift // AccessibleForms.swift struct RegistrationForm: View { @State private var email = "" @State private var password = "" @State private var emailError: String? @State private var passwordError: String? var body: some View { Form { Section { TextField("Email", text: $email) .textContentType(.emailAddress) .keyboardType(.emailAddress) .accessibilityLabel("Email address") .accessibilityHint(emailError != nil ? "Error: \(emailError!)" : nil) if let error = emailError { Text(error) .foregroundColor(.red) .font(.caption) .accessibilityLabel("Email error: \(error)") } } Section { SecureField("Password", text: $password) .textContentType(.newPassword) .accessibilityLabel("Password") .accessibilityHint(passwordHint) PasswordStrengthIndicator(password: password) } Button("Create account") { submitForm() } .disabled(!isFormValid) .accessibilityHint(isFormValid ? "Double-tap to create your account" : "Form incomplete") } } var passwordHint: String { if let error = passwordError { return "Error: \(error)" } return "Minimum 8 characters with uppercase and numbers" } } // Accessible password strength indicator struct PasswordStrengthIndicator: View { let password: String var strength: PasswordStrength { // Calculation logic PasswordStrength.calculate(password) } var body: some View { HStack(spacing: 4) { ForEach(0..<4) { index in Rectangle() .fill(index < strength.level ? strength.color : Color.gray.opacity(0.3)) .frame(height: 4) } } .accessibilityElement(children: .ignore) .accessibilityLabel("Password strength") .accessibilityValue(strength.description) // "Weak", "Medium", "Strong", "Very strong" } } ``` Accessibility-Hints kommunizieren Fehler und Anweisungen, ohne die visuelle Oberfläche zu überladen. ## Audits und Tests der Barrierefreiheit ### 14. Wie auditiert man die Barrierefreiheit einer iOS-App? Ein Audit kombiniert automatisierte Werkzeuge und manuelle Tests. Der Accessibility Inspector von Xcode analysiert Elemente, VoiceOver validiert die reale Nutzererfahrung und Unit-Tests prüfen Accessibility-Eigenschaften. ```swift // AccessibilityAudit.swift // Unit test accessibility properties import XCTest @testable import MyApp class AccessibilityTests: XCTestCase { func testProductCardAccessibility() { let product = Product(name: "iPhone", price: "$999", rating: "4.5") let view = ProductCardView(product: product) // Verify element is accessible XCTAssertTrue(view.isAccessibilityElement) // Verify label XCTAssertEqual( view.accessibilityLabel, "iPhone, $999, 4.5 stars" ) // Verify traits XCTAssertTrue(view.accessibilityTraits.contains(.button)) } func testDynamicTypeSupport() { let label = UILabel() label.font = UIFont.preferredFont(forTextStyle: .body) // Verify automatic adjustment XCTAssertTrue(label.adjustsFontForContentSizeCategory) } } // UI test with simulated VoiceOver class AccessibilityUITests: XCTestCase { func testLoginFlowAccessibility() { let app = XCUIApplication() app.launch() // Access elements by accessibility label let emailField = app.textFields["Email address"] XCTAssertTrue(emailField.exists) emailField.tap() emailField.typeText("test@example.com") let passwordField = app.secureTextFields["Password"] XCTAssertTrue(passwordField.exists) let loginButton = app.buttons["Sign in"] XCTAssertTrue(loginButton.exists) XCTAssertTrue(loginButton.isEnabled) } // Automatic audit iOS 17+ func testAccessibilityAudit() throws { let app = XCUIApplication() app.launch() // Automatic screen audit try app.performAccessibilityAudit() } } ``` Das automatische Audit unter iOS 17+ erkennt häufige Probleme: fehlende Labels, ungenügenden Kontrast, zu kleine Elemente. ### 15. Welche Accessibility-Fehler sind am häufigsten? Häufige Fehler sind fehlende Labels, nicht beschriebene Bilder, fehlende Dynamic-Type-Unterstützung und interaktive Elemente ohne passende Traits. ```swift // CommonMistakes.swift // WRONG: Button without accessible label Button { performAction() } label: { Image(systemName: "plus") } // VoiceOver reads: "Button" - useless // CORRECT: Explicit label Button { performAction() } label: { Image(systemName: "plus") } .accessibilityLabel("Add item") // WRONG: Fixed font size Text("Important") .font(.system(size: 16)) // Doesn't respect Dynamic Type // CORRECT: Semantic text style Text("Important") .font(.body) // Adapts to preferences // WRONG: Informative image without description Image("product-photo") // CORRECT: Content description Image("product-photo") .accessibilityLabel("Product photo: Black audio headphones") // WRONG: Clickable element without button trait Text("Learn more") .onTapGesture { showDetails() } // VoiceOver doesn't know it's interactive // CORRECT: Appropriate traits Text("Learn more") .onTapGesture { showDetails() } .accessibilityAddTraits(.isButton) .accessibilityHint("Double-tap to show details") // WRONG: Insufficient contrast Text("Light gray text") .foregroundColor(.gray.opacity(0.4)) // CORRECT: Minimum contrast ratio 4.5:1 Text("Readable text") .foregroundColor(.secondary) // Respects guidelines // WRONG: Touch target too small Button { } label: { Image(systemName: "xmark") .font(.caption) // Too small (< 44x44 points) } // CORRECT: Minimum 44x44 point area Button { } label: { Image(systemName: "xmark") } .frame(minWidth: 44, minHeight: 44) ``` Diese Fehler lassen sich mit dem Accessibility Inspector erkennen und mit wenigen Codezeilen beheben. ## Fazit Die iOS-Barrierefreiheit ruht auf drei Säulen: VoiceOver für sehbehinderte Nutzer, Dynamic Type für die Textanpassung und semantische Traits für eine konsistente Navigation. Die Beherrschung dieser Konzepte demonstriert professionelles Know-how, das Arbeitgeber aktiv suchen. ### Prüfliste - VoiceOver mit passenden Labels, Hints und Traits konfigurieren - Dynamic Type mit semantischen Textstilen umsetzen - Layouts an extreme Accessibility-Größen anpassen - Elemente für effiziente Navigation gruppieren - Fokus nach Oberflächenänderungen programmatisch steuern - Eigene Steuerungen anpassbar machen - Regelmäßig mit dem Accessibility Inspector und automatisierten Tests auditieren - Häufige Fehler vermeiden: fehlende Labels, unbeschriebene Bilder, unzureichender Kontrast ### Weitere Ressourcen Die offizielle Apple-Dokumentation "Human Interface Guidelines - Accessibility" bleibt die zentrale Referenz. Regelmäßiges Testen mit aktiviertem VoiceOver hilft, Probleme aufzudecken, die automatische Tools nicht erfassen. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/ios/ios-accessibility-interview-voiceover-dynamic-type