From 2d35c95219facdbfa3602306ee758a5c7d542c78 Mon Sep 17 00:00:00 2001 From: Xavier Daleau Date: Mon, 22 Jan 2024 13:52:50 +0100 Subject: [PATCH] [Accessibility] Turn UIKit Tab into an accessibility container --- .../Tab/View/UIKit/TabItemUIView.swift | 46 ++++++++++++++----- .../Components/Tab/View/UIKit/TabUIView.swift | 11 +++-- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/core/Sources/Components/Tab/View/UIKit/TabItemUIView.swift b/core/Sources/Components/Tab/View/UIKit/TabItemUIView.swift index 58526e753..c78a33b1b 100644 --- a/core/Sources/Components/Tab/View/UIKit/TabItemUIView.swift +++ b/core/Sources/Components/Tab/View/UIKit/TabItemUIView.swift @@ -66,6 +66,12 @@ public final class TabItemUIView: UIControl { return self.viewModel.isSelected } set { + if newValue { + self.accessibilityTraits.insert(.selected) + }else { + self.accessibilityTraits.remove(.selected) + } + guard newValue != self.viewModel.isSelected else { return } self.viewModel.updateState(isSelected: newValue) } } @@ -139,7 +145,7 @@ public final class TabItemUIView: UIControl { newBadge.isHidden.toggle() newBadge.isHidden.toggle() } - + self.invalidateIntrinsicContentSize() } } @@ -236,15 +242,6 @@ public final class TabItemUIView: UIControl { } } - public override var isHighlighted: Bool { - get { - return self.viewModel.isPressed - } - set { - self.viewModel.updateState(isPressed: newValue) - } - } - /// A Boolean value indicating whether the control is in the enabled state. /// /// Set the value of this property to true to enable the control or false to disable it. An enabled control is capable of responding to user interactions, whereas a disabled control ignores touch events and may draw itself differently. @@ -254,7 +251,13 @@ public final class TabItemUIView: UIControl { return self.viewModel.isEnabled } set { - self.viewModel.updateState(isEnabled: newValue) + if newValue { + self.accessibilityTraits.remove(.notEnabled) + }else { + self.accessibilityTraits.insert(.notEnabled) + } + guard newValue != self.viewModel.isEnabled else { return } + self.viewModel.isEnabled = newValue } } @@ -338,6 +341,8 @@ public final class TabItemUIView: UIControl { self.setupConstraints() self.enableTouch() self.setupSubscriptions() + self.isAccessibilityElement = true + self.accessibilityTraits.insert(.button) } required init?(coder: NSCoder) { @@ -363,6 +368,22 @@ public final class TabItemUIView: UIControl { self.setNeedsLayout() } + // MARK: - Control functions + public override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + self.viewModel.isPressed = true + } + + public override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + self.viewModel.isPressed = false + } + + public override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + self.viewModel.isPressed = false + } + // MARK: - Private functions private func setupSubscriptions() { self.viewModel.$tabStateAttributes.subscribe(in: &self.subscriptions) { [weak self] attributes in @@ -391,7 +412,7 @@ public final class TabItemUIView: UIControl { self.bringSubviewToFront(self.bottomLine) self.setupColors(attributes: self.viewModel.tabStateAttributes) - + self.addOrRemoveIcon(self.viewModel.content.icon) self.addOrRemoveTitle(self.viewModel.content.title) } @@ -471,6 +492,7 @@ public final class TabItemUIView: UIControl { self.label.textColor = self.viewModel.tabStateAttributes.colors.label.uiColor self.label.text = text + self.accessibilityLabel = text self.label.isHidden = text == nil self.invalidateIntrinsicContentSize() diff --git a/core/Sources/Components/Tab/View/UIKit/TabUIView.swift b/core/Sources/Components/Tab/View/UIKit/TabUIView.swift index eced6bd82..68a1208db 100644 --- a/core/Sources/Components/Tab/View/UIKit/TabUIView.swift +++ b/core/Sources/Components/Tab/View/UIKit/TabUIView.swift @@ -211,6 +211,7 @@ public final class TabUIView: UIControl { self.setupConstraints() self.enableTouch() self.setupSubscriptions() + self.setupAccessibility() } required init?(coder: NSCoder) { @@ -462,9 +463,6 @@ public final class TabUIView: UIControl { // MARK: - Private Functions private func setupViews(items: [TabUIItemContent]) { - - self.accessibilityIdentifier = TabAccessibilityIdentifier.tab - let tabItemViews = items.map{ item in return TabItemUIView( theme: theme, @@ -517,6 +515,12 @@ public final class TabUIView: UIControl { stackView.distribution = self.apportionsSegmentWidthsByContent ? .fill : .fillEqually } + private func setupAccessibility() { + self.accessibilityTraits.insert(.tabBar) + self.isAccessibilityElement = false + self.accessibilityContainerType = .semanticGroup + } + private func setTabItems(content: [TabUIItemContent]) { self.viewModel.content = content @@ -530,6 +534,7 @@ public final class TabUIView: UIControl { } self.stackView.removeArrangedSubviews() self.stackView.addArrangedSubviews(items) + self.accessibilityElements?.append(contentsOf: items) self.updateAccessibilityIdentifiers() self.invalidateIntrinsicContentSize()