From 01923afe4aed53305eb4c6eb5388ad0bb14ff572 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Sat, 26 Aug 2023 10:24:17 -0500 Subject: [PATCH] refactored for accessible elements Signed-off-by: Matt Bruce --- VDSSample/Protocols/CustomRotorable.swift | 83 +++++++++-------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/VDSSample/Protocols/CustomRotorable.swift b/VDSSample/Protocols/CustomRotorable.swift index 66c64e8..111b1af 100644 --- a/VDSSample/Protocols/CustomRotorable.swift +++ b/VDSSample/Protocols/CustomRotorable.swift @@ -13,79 +13,62 @@ public protocol CustomRotorable: UIViewController { } extension CustomRotorable { - - /// Adds CustomRotor to the accessibilityCustomRotors array. - /// - Parameters: - /// - name: Name that will show up in the Rotor picker. - /// - trait: Any UIView that has this traits will be added to this Name. + internal func addCustomRotor(with name: String, for trait: UIAccessibilityTraits) { - //filter out old rotors with same name accessibilityCustomRotors = (accessibilityCustomRotors ?? []).filter { $0.name != name } - - //create new rotor + let newRotor = UIAccessibilityCustomRotor(name: name) { [weak self] predicate in - guard let self else { return nil } - - let views = self.view.accessibleElements(with: trait) - - guard !views.isEmpty else { return nil } + guard let self = self else { return nil } + + let elements = self.view.accessibleElements(with: trait) + + guard !elements.isEmpty else { return nil } - let currentIndex = views.firstIndex(where: { $0 === predicate.currentItem.targetElement }) - let count = views.count - - //find the nextIndex + let currentIndex = elements.firstIndex(where: { ($0 as AnyObject) === predicate.currentItem.targetElement }) + let count = elements.count + let nextIndex: Int switch predicate.searchDirection { case .next: - if let currentIndex, currentIndex != count - 1{ - //go forwards - nextIndex = currentIndex + 1 - } else { - //get the first - nextIndex = 0 - } + nextIndex = currentIndex.map { ($0 + 1) % count } ?? 0 case .previous: - if let currentIndex, currentIndex != 0 { - //go backwards - nextIndex = currentIndex - 1 - } else { - //get the last - nextIndex = count - 1 - } + nextIndex = currentIndex.map { ($0 - 1 + count) % count } ?? 0 @unknown default: - //get the first nextIndex = 0 } - - return UIAccessibilityCustomRotorItemResult(targetElement: views[nextIndex], targetRange: nil) + + guard let element = elements[nextIndex] as? NSObjectProtocol else { return nil } + return UIAccessibilityCustomRotorItemResult(targetElement: element, targetRange: nil) } - - //append rotor + accessibilityCustomRotors?.append(newRotor) } - - /// Loads all of the custom rotors for the screen. + public func loadCustomRotors() { customRotors.forEach { addCustomRotor(with: $0.name, for: $0.trait) } } } public extension UIView { - - /// Gets all of the Views that has the matching accessibilityTrait. - /// - Parameter trait: This is the trailt for the accessibilityTrait property of a view. - /// - Returns: An array of RotorItemResult - func accessibleElements(with trait: UIAccessibilityTraits) -> [UIView] { - var elements: [UIView] = [] - - //add your self if you meet the requirements + + func accessibleElements(with trait: UIAccessibilityTraits) -> [Any] { + var elements: [Any] = [] + if isAccessibilityElement, accessibilityTraits.contains(trait) { elements.append(self) } - - //loop through your subviews - subviews.forEach { elements.append(contentsOf: $0.accessibleElements(with: trait)) } - + + if let customAccessibilityElements = accessibilityElements { + elements.append(contentsOf: customAccessibilityElements.filter { element in + if let element = element as? UIAccessibilityElement { + return element.accessibilityTraits.contains(trait) + } + return false + }) + } else { + subviews.forEach { elements.append(contentsOf: $0.accessibleElements(with: trait)) } + } + return elements } }