diff --git a/Example/AccessibilitySnapshot/SwitchControlViewController.swift b/Example/AccessibilitySnapshot/SwitchControlViewController.swift index 1f2918b5..a7ec152d 100644 --- a/Example/AccessibilitySnapshot/SwitchControlViewController.swift +++ b/Example/AccessibilitySnapshot/SwitchControlViewController.swift @@ -91,26 +91,36 @@ private extension SwitchControlViewController { switchControls.forEach { addSubview($0) } + let switchTrait = UIAccessibilityTraits(rawValue: 0x0020000000000000) + // Add a fake switch that has the switch button trait only, but is not a UISwitch. - fakeSwitchView.isAccessibilityElement = true - fakeSwitchView.accessibilityLabel = "Fake Label" - fakeSwitchView.accessibilityValue = "Value" - fakeSwitchView.accessibilityTraits.insert(UIAccessibilityTraits(rawValue: 0x0020000000000000)) - fakeSwitchView.frame.size = .init(width: 48, height: 32) - fakeSwitchView.backgroundColor = .lightGray - fakeSwitchView.layer.cornerRadius = 16 - addSubview(fakeSwitchView) - - // Add a fake switch that has the switch button and button traits, but is not a UISwitch. - fakeSwitchButton.isAccessibilityElement = true - fakeSwitchButton.accessibilityLabel = "Fake Label" - fakeSwitchButton.accessibilityValue = "Value" - fakeSwitchButton.accessibilityTraits.insert(.button) - fakeSwitchButton.accessibilityTraits.insert(UIAccessibilityTraits(rawValue: 0x0020000000000000)) - fakeSwitchButton.frame.size = .init(width: 48, height: 32) - fakeSwitchButton.backgroundColor = .lightGray - fakeSwitchButton.layer.cornerRadius = 16 - addSubview(fakeSwitchButton) + for fakeSwitchView in fakeSwitchViews { + fakeSwitchView.isAccessibilityElement = true + fakeSwitchView.accessibilityLabel = "Fake Label" + fakeSwitchView.frame.size = .init(width: 48, height: 32) + fakeSwitchView.backgroundColor = .lightGray + fakeSwitchView.layer.cornerRadius = 16 + } + + fakeSwitchViews[0].accessibilityValue = "1" + fakeSwitchViews[0].accessibilityTraits = [switchTrait, .button] + + fakeSwitchViews[1].accessibilityValue = "0" + fakeSwitchViews[1].accessibilityTraits = [switchTrait, .button] + + fakeSwitchViews[2].accessibilityValue = "2" + fakeSwitchViews[2].accessibilityTraits = [switchTrait, .button] + + fakeSwitchViews[3].accessibilityValue = "1" + fakeSwitchViews[3].accessibilityTraits = [switchTrait] + + fakeSwitchViews[4].accessibilityValue = "3" + fakeSwitchViews[4].accessibilityTraits = [switchTrait] + + fakeSwitchViews[5].accessibilityValue = "Value" + fakeSwitchViews[5].accessibilityTraits = [.button, switchTrait] + + fakeSwitchViews.forEach { addSubview($0) } } @available(*, unavailable) @@ -122,11 +132,8 @@ private extension SwitchControlViewController { private let switchControls: [UISwitch] = (0..<9).map { _ in UISwitch() } - /// UIView with the switch button trait that acts like a switch, but is not a UISwitch. - private let fakeSwitchView: UIView = .init() - - /// UIView with the button and switch button traits that acts like a switch, but is not a UISwitch. - private let fakeSwitchButton: UIView = .init() + /// `UIView`s with the switch button trait that act like a switch, but aren't actually switches. + private let fakeSwitchViews: [UIView] = (0..<6).map { _ in UIView() } // MARK: - UIView @@ -136,18 +143,10 @@ private extension SwitchControlViewController { let statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 var distributionSpecifiers: [ViewDistributionSpecifying] = [ statusBarHeight.fixed, 1.flexible ] - for subview in switchControls { + for subview in (switchControls + fakeSwitchViews) { distributionSpecifiers.append(subview) distributionSpecifiers.append(1.flexible) } - distributionSpecifiers.append( - contentsOf: [ - fakeSwitchView.distributionItem, - 1.flexible, - fakeSwitchButton.distributionItem, - 1.flexible, - ] - ) applyVerticalSubviewDistribution(distributionSpecifiers) } diff --git a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_13_7_375x812@3x.png b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_13_7_375x812@3x.png index 3ed69a4e..e93907c0 100644 Binary files a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_13_7_375x812@3x.png and b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_13_7_375x812@3x.png differ diff --git a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_14_5_390x844@3x.png b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_14_5_390x844@3x.png index 8bc08b51..0093a994 100644 Binary files a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_14_5_390x844@3x.png and b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_14_5_390x844@3x.png differ diff --git a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_16_4_393x852@3x.png b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_16_4_393x852@3x.png index 8f2d632e..1c4a22d1 100644 Binary files a/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_16_4_393x852@3x.png and b/Example/SnapshotTests/ReferenceImages/_64/SnapshotTests.AccessibilitySnapshotTests/testSwitchControls_16_4_393x852@3x.png differ diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Assets/de.lproj/Localizable.strings b/Sources/AccessibilitySnapshot/Core/Swift/Assets/de.lproj/Localizable.strings index decd8fee..4ee84b4d 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Assets/de.lproj/Localizable.strings +++ b/Sources/AccessibilitySnapshot/Core/Swift/Assets/de.lproj/Localizable.strings @@ -35,13 +35,16 @@ "trait.search_field.description" = "Suchfeld."; /* Description for the 'switch button' accessibility trait, when the switch is on */ -"trait.switch_button.state_on.description" = "Umschalttaste. Ein."; +"trait.switch_button.state_on.description" = "Ein."; /* Description for the 'switch button' accessibility trait, when the switch is off */ -"trait.switch_button.state_off.description" = "Umschalttaste. Aus."; +"trait.switch_button.state_off.description" = "Aus."; -/* Description for the 'switch button' accessibility trait, when the state of the switch cannot be determined */ -"trait.switch_button.state_unspecified.description" = "Umschalttaste."; +/* Description for the 'switch button' accessibility trait, when the switch is in a mixed state */ +"trait.switch_button.state_mixed.description" = "Gemischt."; + +/* Description for the 'switch button' accessibility trait */ +"trait.switch_button.description" = "Umschalttaste."; /* Hint describing how to use elements with the 'switch button' accessibility trait */ "trait.switch_button.hint" = "Zum Umschalten Doppeltippen."; diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Assets/en.lproj/Localizable.strings b/Sources/AccessibilitySnapshot/Core/Swift/Assets/en.lproj/Localizable.strings index b2ef9364..5cfd8276 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Assets/en.lproj/Localizable.strings +++ b/Sources/AccessibilitySnapshot/Core/Swift/Assets/en.lproj/Localizable.strings @@ -35,13 +35,16 @@ "trait.search_field.description" = "Search Field."; /* Description for the 'switch button' accessibility trait, when the switch is on */ -"trait.switch_button.state_on.description" = "Switch Button. On."; +"trait.switch_button.state_on.description" = "On."; /* Description for the 'switch button' accessibility trait, when the switch is off */ -"trait.switch_button.state_off.description" = "Switch Button. Off."; +"trait.switch_button.state_off.description" = "Off."; -/* Description for the 'switch button' accessibility trait, when the state of the switch cannot be determined */ -"trait.switch_button.state_unspecified.description" = "Switch Button."; +/* Description for the 'switch button' accessibility trait, when the switch is in a mixed state */ +"trait.switch_button.state_mixed.description" = "Mixed."; + +/* Description for the 'switch button' accessibility trait */ +"trait.switch_button.description" = "Switch Button."; /* Hint describing how to use elements with the 'switch button' accessibility trait */ "trait.switch_button.hint" = "Double tap to toggle setting."; diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Assets/ru.lproj/Localizable.strings b/Sources/AccessibilitySnapshot/Core/Swift/Assets/ru.lproj/Localizable.strings index 0e11aec8..11220650 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Assets/ru.lproj/Localizable.strings +++ b/Sources/AccessibilitySnapshot/Core/Swift/Assets/ru.lproj/Localizable.strings @@ -35,13 +35,16 @@ "trait.search_field.description" = "Поле поиска."; /* Description for the 'switch button' accessibility trait, when the switch is on */ -"trait.switch_button.state_on.description" = "Кнопка-переключатель. Вкл."; +"trait.switch_button.state_on.description" = "Вкл."; /* Description for the 'switch button' accessibility trait, when the switch is off */ -"trait.switch_button.state_off.description" = "Кнопка-переключатель. Выкл."; +"trait.switch_button.state_off.description" = "Выкл."; -/* Description for the 'switch button' accessibility trait, when the state of the switch cannot be determined */ -"trait.switch_button.state_unspecified.description" = "Кнопка-переключатель."; +/* Description for the 'switch button' accessibility trait, when the switch is in a mixed state */ +"trait.switch_button.state_mixed.description" = "Смешанно."; + +/* Description for the 'switch button' accessibility trait */ +"trait.switch_button.description" = "Кнопка-переключатель."; /* Hint describing how to use elements with the 'switch button' accessibility trait */ "trait.switch_button.hint" = "Коснитесь дважды, чтобы переключить настройку."; diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIAccessibility+SnapshotAdditions.swift b/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIAccessibility+SnapshotAdditions.swift index f01074e7..ad0fa500 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIAccessibility+SnapshotAdditions.swift +++ b/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIAccessibility+SnapshotAdditions.swift @@ -107,19 +107,23 @@ extension NSObject { } if accessibilityTraits.contains(.switchButton) { - if let `self` = self as? UISwitch { - if self.isOn { - traitSpecifiers.append(strings.switchButtonOnTraitName) - } else { - traitSpecifiers.append(strings.switchButtonOffTraitName) - } + if accessibilityTraits.contains(.button) { + // An element can have the private switch button trait without being a UISwitch (for example, by passing + // through the traits of a contained switch). In this case, VoiceOver will still read the "Switch + // Button." trait, but only if the element's traits also include the `.button` trait. + traitSpecifiers.append(strings.switchButtonTraitName) + } - } else if accessibilityTraits.contains(.button) { - // An element can have the private switch button trait without being a UISwitch (for example, by passing through - // the traits of a contained switch). In this case, VoiceOver will still read the "Switch Button." trait, but - // will not read whether or not the switch is turned on. If the element's traits do not also include the `.button` - // trait, VoiceOver will not read the trait description. - traitSpecifiers.append(strings.switchButtonStatelessTraitName) + switch accessibilityValue { + case "1": + traitSpecifiers.append(strings.switchButtonOnStateName) + case "0": + traitSpecifiers.append(strings.switchButtonOffStateName) + case "2": + traitSpecifiers.append(strings.switchButtonMixedStateName) + default: + // When the switch button trait is set, unknown accessibility values are omitted from the description. + break } } @@ -304,11 +308,13 @@ extension NSObject { let searchFieldTraitName: String - let switchButtonOnTraitName: String + let switchButtonTraitName: String - let switchButtonOffTraitName: String + let switchButtonOnStateName: String - let switchButtonStatelessTraitName: String + let switchButtonOffStateName: String + + let switchButtonMixedStateName: String let switchButtonTraitHint: String @@ -396,19 +402,24 @@ extension NSObject { comment: "Description for the 'search field' accessibility trait", locale: locale ) - self.switchButtonOnTraitName = "Switch Button. On.".localized( + self.switchButtonTraitName = "Switch Button.".localized( + key: "trait.switch_button.description", + comment: "Description for the 'switch button' accessibility trait", + locale: locale + ) + self.switchButtonOnStateName = "On.".localized( key: "trait.switch_button.state_on.description", comment: "Description for the 'switch button' accessibility trait, when the switch is on", locale: locale ) - self.switchButtonOffTraitName = "Switch Button. Off.".localized( + self.switchButtonOffStateName = "Off.".localized( key: "trait.switch_button.state_off.description", comment: "Description for the 'switch button' accessibility trait, when the switch is off", locale: locale ) - self.switchButtonStatelessTraitName = "Switch Button.".localized( - key: "trait.switch_button.state_unspecified.description", - comment: "Description for the 'switch button' accessibility trait, when the state of the switch cannot be determined", + self.switchButtonMixedStateName = "Mixed.".localized( + key: "trait.switch_button.state_mixed.description", + comment: "Description for the 'switch button' accessibility trait, when the switch is in a mixed state", locale: locale ) self.switchButtonTraitHint = "Double tap to toggle setting.".localized(