1

The problem is that when cells are reusable, accesibilityLabel doesn't work and VoiceOver reads zero or one when i switch to another cell with VoiceOver

How can I set value to accessibilityLabel when new cells are loaded?

I attach my code

Celda.swift

class Celda: UITableViewCell {
    @IBOutlet weak var label: UILabel!

    func setup(_ number: String) {
        label.text = number
    }

    override var isAccessibilityElement: Bool {
        get {return false }
        set { self.isAccessibilityElement = newValue}
    }


    private var _accessibilityElements: [Any]?

    override var accessibilityElements: [Any]? {
        get {
            if let _accessibilityElements = _accessibilityElements {
                return _accessibilityElements
            }
            var elements = [UIAccessibilityElement]()
            let cellAccessibility = UIAccessibilityElement(accessibilityContainer: self)
            cellAccessibility.accessibilityFrameInContainerSpace = self.contentView.frame
            cellAccessibility.accessibilityLabel = label.text
            cellAccessibility.isAccessibilityElement = true

            elements.append(cellAccessibility)
            _accessibilityElements = elements
            return _accessibilityElements
        }
        set {
            _accessibilityElements = newValue
        }
    }
}

ViewController.swift

class ViewController: UIViewController {

    var elementos = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"];

    @IBOutlet weak var tabla: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tabla.dataSource = self
        tabla.delegate = self
        tabla.reloadData()
    }
}

extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return elementos.count;
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let celda: Celda =  tableView .dequeueReusableCell(withIdentifier: "Celda", for: indexPath) as! Celda
        celda.setup(elementos[indexPath.row])
        return celda
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 900.0
    }
}

Can I set accessibilityLabel for the other cells?

I need a solution scalable and that UIAccessibilityLabel be the one who defines his own accessiblityLabel

2 Answers2

2

You need to set it inside cellForRowAt

celda.setup(elementos[indexPath.row],value:"\(indexPath.row)")

func setup(_ number: String,value:String) {
  label.text = number
  label.accessibilityLabel = value
}

So every dequeue it's overwritten to the current indexPath

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • It works in this example, but it's not good for me. I think it's not scalable in general. I believe that UIAccessibilityElement should be the one who defines his own accessibilityLabel. I set index.row but it could be another value or, for example, if I want to set isAccessibilityElement = false just for odd cells – dsanchezarroyo Jun 12 '19 at 16:09
0

I need a solution scalable and that UIAccessibilityLabel be the one who defines his own accessiblityLabel.

To reach your goal, you need to reset all the cell properties before using it for new refreshed data: take a look at the prepareForReuse table view cell function.

...for example, if I want to set isAccessibilityElement = false just for odd cells

Insert the code snippets hereunder in Celda.swift first:

func setup(_ number: String, a11y isA11y: Bool) {
    label.text = number
    isAccessibilityElement = isA11y
}

override func prepareForReuse() {
    super.prepareForReuse()

    _accessibilityElements = nil
    _isAccessibilityElement = false
    label.text = "NADA"
}

private var _isAccessibilityElement: Bool?

override var isAccessibilityElement: Bool {
    get { return _isAccessibilityElement ?? false  }
    set { _isAccessibilityElement = newValue }
}

private var _accessibilityElements: [Any]?

override var accessibilityElements: [Any]? {
    get {
        if let _accessibilityElements = _accessibilityElements {
            return _accessibilityElements
        }
        var elements = [UIAccessibilityElement]()
        let cellAccessibility = UIAccessibilityElement(accessibilityContainer: self)
        cellAccessibility.accessibilityFrameInContainerSpace = self.contentView.frame
        cellAccessibility.accessibilityLabel = label.text
        cellAccessibility.isAccessibilityElement = self.isAccessibilityElement

        elements.append(cellAccessibility)
        _accessibilityElements = elements
        return _accessibilityElements
    }
    set { _accessibilityElements = newValue }
}

... and in ViewController.swift:

func tableView(_ tableView: UITableView,
               cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let celda: Celda =  tableView .dequeueReusableCell(withIdentifier: "Celda",
                                                       for: indexPath) as! Celda

    let isA11yCell = (Int(elementos[indexPath.row])! % 2) == 0 ? true : false

    celda.setup(elementos[indexPath.row],
                a11y: isA11yCell)
    return celda
}

Can I set accessibilityLabel for the other cells? I need a solution scalable...

This solution is scalable and it's up to you to adapt its content to your app environment.

XLE_22
  • 5,124
  • 3
  • 21
  • 72