How to delete uiAccessibility voice over custom rotors

203 Views Asked by At

We use a complex calendar screen. (Best is to rewrite everything, but that is unfortunate not an option now). This screen allows to switch between a day overview, a week overview and a month overview. Depending on the view we want to have different rotors.

  • Day overview has no rotors and is a simple tableViewController
  • the week has rotors for every day of the week, and is a collectionView.
  • the month has rotors for every day that has anything planned on that day, and is a collection of tableviews per day.

there's a top view controller (CalendarViewController) which has several other (non-interesting for this code) viewControllers and a ContainerSwitchViewController which is based on https://github.com/levigroker/GRKContainerViewController . Basically it replaces it's content with one of the three view controllers (day, week, month).

Every time the view controllers the viewDidLoad is called on those viewControllers and in the viewDidLoad i create a custom rotor. In the week overview i use this code to create a custom rotor for every day of the week.

private func customRotorFor(weekday: weekday) -> UIAccessibilityCustomRotor {
    UIAccessibilityCustomRotor(name: weekday.toString()) { predicate in
        let currentElement = predicate.currentItem.targetElement as? CalendarWeekOverviewCollectionViewCell
        let eventsOfTheDay = self.eventsOfTheDay(for: weekday)
        let currentIndex = eventsOfTheDay.firstIndex { $0 == currentElement }
        let targetIndex: Int
        switch predicate.searchDirection {
        case .previous:
            targetIndex = (currentIndex ?? 1) - 1
        case .next:
            targetIndex = (currentIndex ?? -1) + 1
        }
        guard 0..<eventsOfTheDay.count ~= targetIndex else { return nil } // reached boundary
        let targetElement = eventsOfTheDay[targetIndex]
        return UIAccessibilityCustomRotorItemResult(targetElement: targetElement, targetRange: nil)
    }
}

this creates the correct rotor for me and reads and navigates exactly as i want, the UIAccessibilityCustomRotor.Search codeblock is working fine.

I call this function in viewDidLoad by iterating over all weekday cases

UIApplication.topViewController()?.accessibilityCustomRotors = weekday.allCases.map { self.customRotorFor(weekday: $0) }

with weekday being a simple enum

enum weekday: Int, CaseIterable {
        case monday = 0
        case tuesday = 1
        case wednesday = 2
        case thursday = 3
        case friday = 4
        case saturday = 5
        case sunday = 6
        
        func toString() -> String {
            switch self {
            case .monday: return "maandag"
            case .tuesday: return "dinsdag"
            case .wednesday: return "woensdag"
            case .thursday: return "donderdag"
            case .friday: return "vrijdag"
            case .saturday: return "zaterdag"
            case .sunday: return "zondag"
            }
        }
    }

I can set the custom rotor to the viewController itself (instead of the top application). Only then the rotor is activated when the user is on top of a cell. If there are no, or not many cells the user will have a hard time finding the place to activate the custom rotor. Setting in on the top application viewcontroller it is available at the whole screen which is exactly the behaviour I want.

However, after the first viewDidLoad (the containerswitchviewcontroller defaults to week-overview) setting the UIApplication.topviewcontrollers uiaccessibilityCustomRotors does not get set anymore. I can set the rotors to my custom rotors as described above, and then set it to [] or nil and it does not add them/remove them. If I switch the order of the code and first set it to nil/[] and then to my custom rotors are visible. So I know how I can set or unset the rotors. However, when I try to set this after the initial viewDidLoad this doesn't work and the rotors (including it's items) remain active.

What I want is to remove the accessibility custom rotors (preferable in the viewDidLoad) so that every viewDidLoad can choose to use it's own custom rotors.

I also tried to iniate life-cycle changes using layoutSubViews, loadView etc... and also posting UIAccessibility notifications (.screenchanged and .layoutChanged)

I have also tried setting it to the topviewcontrollers view rather than the view, but that didn't make a difference

0

There are 0 best solutions below