Open
Description
We are trying to override the default iOS VoiceOver read out during the scrolling of a UITableView with RxTableViewSectionedReloadDataSource
binded to it.
After extending our ViewController to UIScrollViewAccessibilityDelegate
and implementing
func accessibilityScrollStatus(for scrollView: UIScrollView) -> String? {
return "Some status"
}
we will receive a crash when VoiceOver is enabled and we are trying to scroll the list.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RxCocoa.RxTableViewDelegateProxy accessibilityScrollStatusForScrollView:]: unrecognized selector sent to instance 0x282a966f0'
To recreate the error, you can simply display this VoiceOverScrollStatusViewController
and scroll down the list with VoiceOver enabled.
import Foundation
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
struct CustomData {
var anInt: Int
var aString: String
}
struct SectionOfCustomData {
var header: String
var items: [Item]
}
extension SectionOfCustomData: SectionModelType {
typealias Item = CustomData
init(original: SectionOfCustomData, items: [Item]) {
self = original
self.items = items
}
}
class VoiceOverScrollStatusViewController: UIViewController {
private let tableView: UITableView
private let disposeBag = DisposeBag()
let rxDataSource = RxTableViewSectionedReloadDataSource<SectionOfCustomData> { (_, tableView, _, itemSource) -> UITableViewCell in
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") else {
return UITableViewCell()
}
cell.textLabel?.text = "Cell \(itemSource.anInt): \(itemSource.aString)"
return cell
}
init() {
if #available(iOS 13.0, *) {
tableView = UITableView(frame: .zero, style: .insetGrouped)
} else {
tableView = UITableView(frame: .zero, style: .grouped)
}
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - view lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
rxDataSource.titleForHeaderInSection = { dataSource, index in
return dataSource.sectionModels[index].header
}
let sections = [
SectionOfCustomData(header: "First Section", items: [.init(anInt: 1, aString: "First"),
.init(anInt: 2, aString: "Zweiter"),
.init(anInt: 3, aString: "Third")]),
SectionOfCustomData(header: "Second Section", items: [.init(anInt: 1, aString: "First"),
.init(anInt: 2, aString: "Zweiter")]),
SectionOfCustomData(header: "Third Section", items: [.init(anInt: 1, aString: "First"),
.init(anInt: 2, aString: "Zweiter"),
.init(anInt: 3, aString: "Third")]),
SectionOfCustomData(header: "Fourth Section", items: [.init(anInt: 1, aString: "First")]),
SectionOfCustomData(header: "Fifth Section", items: [.init(anInt: 1, aString: "First"),
.init(anInt: 2, aString: "Second"),
.init(anInt: 3, aString: "Third")])
]
Observable.just(sections)
.bind(to: tableView.rx.items(dataSource: rxDataSource))
.disposed(by: disposeBag)
}
private func setupTableView() {
tableView.backgroundColor = UIColor(hex: "#F3F5F8")
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
if #available(iOS 11.0, *) {
let guide = view.safeAreaLayoutGuide
tableView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
} else {
tableView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
tableView.delegate = self
}
}
extension VoiceOverScrollStatusViewController: UITableViewDelegate {
}
extension VoiceOverScrollStatusViewController: UIScrollViewAccessibilityDelegate {
func accessibilityScrollStatus(for scrollView: UIScrollView) -> String? {
return "Some status"
}
}
Metadata
Metadata
Assignees
Labels
No labels