85 lines
2.6 KiB
Swift
85 lines
2.6 KiB
Swift
//
|
|
// AccessibilityCustomRotorable.swift
|
|
// VDS
|
|
//
|
|
// Created by Matt Bruce on 8/24/23.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
public protocol CustomRotorable: UIViewController {
|
|
var customRotors: [CustomRotorType] { get set }
|
|
}
|
|
|
|
extension CustomRotorable {
|
|
|
|
internal func addCustomRotor(with name: String, for trait: UIAccessibilityTraits) {
|
|
accessibilityCustomRotors = (accessibilityCustomRotors ?? []).filter { $0.name != name }
|
|
|
|
let newRotor = UIAccessibilityCustomRotor(name: name) { [weak self] predicate in
|
|
guard let self = self else { return nil }
|
|
|
|
let elements = self.view.accessibleElements(with: trait)
|
|
|
|
guard !elements.isEmpty else { return nil }
|
|
|
|
let currentIndex = elements.firstIndex(where: { ($0 as AnyObject) === predicate.currentItem.targetElement })
|
|
let count = elements.count
|
|
|
|
let nextIndex: Int
|
|
switch predicate.searchDirection {
|
|
case .next:
|
|
nextIndex = currentIndex.map { ($0 + 1) % count } ?? 0
|
|
case .previous:
|
|
nextIndex = currentIndex.map { ($0 - 1 + count) % count } ?? 0
|
|
@unknown default:
|
|
nextIndex = 0
|
|
}
|
|
|
|
guard let element = elements[nextIndex] as? NSObjectProtocol else { return nil }
|
|
return UIAccessibilityCustomRotorItemResult(targetElement: element, targetRange: nil)
|
|
}
|
|
|
|
accessibilityCustomRotors?.append(newRotor)
|
|
}
|
|
|
|
public func loadCustomRotors() {
|
|
customRotors.forEach { addCustomRotor(with: $0.name, for: $0.trait) }
|
|
}
|
|
}
|
|
|
|
public extension UIView {
|
|
|
|
func accessibleElements(with trait: UIAccessibilityTraits) -> [Any] {
|
|
var elements: [Any] = []
|
|
|
|
if isAccessibilityElement, accessibilityTraits.contains(trait) {
|
|
elements.append(self)
|
|
}
|
|
|
|
if let customAccessibilityElements = accessibilityElements {
|
|
elements.append(contentsOf: customAccessibilityElements.filter { element in
|
|
if let element = element as? UIAccessibilityElement {
|
|
return element.accessibilityTraits.contains(trait)
|
|
}
|
|
return false
|
|
})
|
|
}
|
|
|
|
subviews.forEach { elements.append(contentsOf: $0.accessibleElements(with: trait)) }
|
|
|
|
return elements
|
|
}
|
|
}
|
|
|
|
public struct CustomRotorType {
|
|
public var name: String
|
|
public var trait: UIAccessibilityTraits
|
|
|
|
public init(name: String, trait: UIAccessibilityTraits) {
|
|
self.name = name
|
|
self.trait = trait
|
|
}
|
|
}
|