Как правильно реализовать выделение и выделить анимацию на UITableViewCell? - PullRequest
1 голос
/ 15 апреля 2019

Я пытаюсь закодировать UITableViewCell с пользовательской анимацией для состояний выделения и выделения.Я переопределил методы setSelected:animated: и setHighlighted:animated:.Однако эти два метода всегда вызываются с animated:false.Поэтому я не могу определить, какие методы вызываются системой (когда табличное представление очищает выборки) или когда пользователь нажимает.Теперь, для выделения, я мог бы, вероятно, предположить, что он всегда вызывается пользователем, поскольку я не нашел другого способа только программно выделить ячейку.Для setSelected:animated: я должен знать, оживлять или нет.Сначала я не мог найти то, что вызывает setSelected:animated:, во-первых, когда я нажимаю на ячейку, потому что даже после переопределения каждого UITableViewDelegate метода без вызова super, setSelected:animated: откуда-то вызывали.

После поиска дней я разобрал UIKitCore.framework, используя дизассемблер бункера, и обнаружил, что setSelected:animated: фактически вызывается методом touchesEnded:event:.На самом деле существует внутренний setSelected: метод, который вызывает setSelected:animated: с false по умолчанию.Более того, поскольку нет документированного API, который позволяет выделять только ячейку (без выделения) и внутренне, setHighlighted:animated: всегда вызывается с false, так какова цель иметь аргумент animated в сигнатуре этого метода?

Я нашел не так много примеров по этому поводу.Все, что я обнаружил, включает в себя вызов tableView.select:rowAtIndexPath:animated с animated:true вручную, может быть didSelectRow или willSelectRow.Это кажется хаком, потому что дважды вызывает setSelected:animated:.

Я уверен, что я не первый, кто реализует пользовательские анимации для выделения и выделения для UITableViewCell.

Обновление:

Это то, что я реализовал до сих пор, и оно работает, даже несмотря на то, что оно кажется хакерским.

override func setSelected(_ selected: Bool, animated: Bool) {
    guard isSelected != selected else {
        return
    }
    super.setSelected(selected, animated: animated)
    if animated {...}
}

// how can I call animated with true?
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    guard isHighlighted != highlighted else {
        return
    }
    super.setHighlighted(highlighted, animated: animated)
    if animated {...}
}


// overriding the touch handlers doesn't feel right.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    setHighlighted(true, animated: true)
    super.touchesBegan(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    setHighlighted(false, animated: true)
    setSelected(!isSelected, animated: true)
    super.touchesEnded(touches, with: event)
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    setHighlighted(false, animated: true)
    super.touchesCancelled(touches, with: event)
}


Ответы [ 2 ]

1 голос
/ 16 апреля 2019

У меня было изображение в разных ячейках в виде коллекции.

    let imageView: UIImageView = {
    let iv = UIImageView()
    iv.image = UIImage(named: "icon1")?.withRenderingMode(.alwaysTemplate)
    iv.tintColor = UIColor.rgb(red: 91, green: 14, blue: 13)
    return iv
}()
// Highlighted when pressed
override var isHighlighted: Bool {
    didSet {
        imageView.tintColor = isHighlighted ? UIColor.white : UIColor.rgb(red: 91, green: 14, blue: 13)
    }
}
// When selected
override var isSelected: Bool {
    didSet {
        imageView.tintColor = isSelected ? UIColor.white : UIColor.rgb(red: 91, green: 14, blue: 13)
    }
}

Может быть, это дает вам представление.

0 голосов
/ 19 апреля 2019

Я пришел к выводу, что на самом деле не существует 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, вы не знаете, оживить это или нет.Вы можете сохранить локальную переменную в ячейке, чтобы отслеживать ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...