Я пришел к выводу, что на самом деле не существует API для UITableView
до выделения UITableViewCell
программно, как selection , если только вы явно не вызовете setHighlighted:animated:
наэкземпляр ячейки с animated:true
.Я могу подтвердить это после просмотра дизассемблированного кода для UITableView
и UITableViewCell
с использованием Hopper
.
Как правило, setHighlighted:animated:
и setSelected:animated:
вызываются с помощью animated:false
из UIView
сенсорных обработчиков.Есть две внутренние функции API setHighlighted:
и setAnimated:
, которые внутренне передают animated: false
, аналогично следующему:
func setSelected(_ selected: Bool) {
setSelected(selected, animated: false)
}
func setHighlighted(_ highlighted: Bool) {
setHighlighted(highlighted, animated: false)
}
func touches...(...) // the touch handlers {
// setSelected(selected)
// setHighlighted(highlighted)
}
Переопределение сенсорных обработчиков не является правильным решением, потому что происходит много других вещейв реализации super
.Если вы пропустите их, это может повредить внутреннее состояние ячейки.Однако в тот момент, когда вы вызываете super.touchesBegan
или любой другой сенсорный обработчик, методы выбора и выделения будут вызываться с помощью animated: false
.
Более того, из документации Apple кажется, что выдолжен переопределить все обработчики касания, если вы решите переопределить один.
Если вы переопределите этот метод без вызова super (шаблон общего пользования), вы также должны переопределить другие методы для обработки событий касания,даже если ваши реализации ничего не делают.
Мое решение
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
return indexPath
}
func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
tableView.deselectRow(at: indexPath, animated: true)
return indexPath
}
Вы должны вернуть indexPath
из этих обработчиков, так как в противном случае методы делегата не будут вызваны.Однако это означает, что теперь вы будете звонить на setSelected:animated:
дважды.Это можно предотвратить с помощью guard
, как показано ниже.
override func setSelected(_ selected: Bool, animated: Bool) {
guard isSelected != selected else {
return
}
if animated {}
}
Для анимации выделения используйте следующее:
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
let cell = tableView.cellForRow(at: indexPath)
// there is no api on tableview to highlight the cell.
// so you must invoke highlight directly on the cell.
cell?.setHighlighted(true, animated: true)
return true
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
guard isHighlighted != highlighted else {
return
}
if animated {}
}
Однако, это оставляет одну последнюю дыру, то естькогда highlighted == false
, вы не знаете, оживить это или нет.Вы можете сохранить локальную переменную в ячейке, чтобы отслеживать ее.