Как изменить пользовательскую высоту UITableViewCell, когда пользователь выбирает или отменяет ее выбор?

В моем проекте у меня есть UITableView, который каждый раз, когда пользователь нажимает на любую ячейку, высота ячейки увеличивается с отображением некоторого длинного текста внутри ячейки, а при повторном нажатии или нажатии на другую ячейку высота ячейки уменьшается и отображается короткий текст (с некоторой анимацией). )

это мой пользовательский код ячейки:

    class SomeCustomCell: UITableViewCell {
    
    static let identifier = "SomeCustomCellId"

    var shortDescLabel: AvatarLabel!
    var longDescLabel: AvatarLabel!
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        backgroundColor = selected ? UIColor.lightGray.withAlphaComponent(0.5) : .clear
        
        if selected {
            didSelected()
        } else {
            deSelected()
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        selectionStyle = .none
        
        shortDescLabel = AvatarLabel()
        shortDescLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(shortDescLabel)
        
        NSLayoutConstraint.activate([
            shortDescLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            shortDescLabel.topAnchor.constraint(equalTo: topAnchor, constant: 20),
            shortDescLabel.heightAnchor.constraint(equalToConstant: 50),
            shortDescLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10)
        ])
        
        longDescLabel = AvatarLabel()
        longDescLabel.alpha = 0.0
        longDescLabel.numberOfLines = 0
        longdateLabel.isHidden = true
        longDescLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(longDescLabel)
        
        NSLayoutConstraint.activate([
            longDescLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            longDescLabel.topAnchor.constraint(equalTo: topAnchor, constant: 20),
            longDescLabel.heightAnchor.constraint(equalToConstant: 100),
            longDescLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func didSelected() {
        longDescLabel.isHidden      = false
        shortDescLabel.isHidden     = true
        UIView.animate(withDuration: 0.5) { [weak self] in
            
            self?.shortDescLabel.alpha  = 0.0
            self?.longDescLabel.alpha   = 1.0
        }
    }
    
    func deSelected() {
        
        longDescLabel.isHidden      = true
        shortDescLabel.isHidden     = false

        backgroundColor = .clear
        
        UIView.animate(withDuration: 0.5) { [weak self] in
            self?.shortDescLabel.alpha  = 1.0
            self?.longDescLabel.alpha   = 0.0
        }
    }
    
    func setSomeCustomCell(_ someModel: SomeModel) {
        
        shortDescLabel.text = someModel.shortText
        longDescLabel.text  = someModel.longText
    }
    }

и это мой код UITableView:

    extension someViewController: UITableViewDelegate, UITableViewDataSource {
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            
            if someModels.count == 0 {
                tableView.setEmptyView()
            } else {
                tableView.restore()
            }
            
            return someModels.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: SomeCustomCell.identifier) as? SomeCustomCell else {
                return SomeCustomCell()
            }
            let item = someModels[indexPath.row]
            cell. setSomeCustomCell(item)
            
            return cell
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            
            if selectedCellIndexPath == indexPath {
                self.selectedCellIndexPath = nil
                guard let cell = tableView.cellForRow(at: indexPath) as? SomeCustomCell else { return }
                cell.deSelected()
            } else {
                self.selectedCellIndexPath = indexPath
            }
    
            tableView.beginUpdates()
            tableView.endUpdates()
            if selectedCellIndexPath != nil {
                // This ensures, that the cell is fully visible once expanded
                tableView.scrollToRow(at: indexPath, at: .none, animated: true)
            }
        }
        
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            if selectedCellIndexPath == indexPath {
                return 140
            }
            return 90
        }
        }

но есть проблема, когда пользователь нажимает на какую-либо ячейку и снова нажимает на нее (ячейка сначала становится большой, а затем становится маленькой) и прокручивает вниз (выбранная ячейка больше не отображается на экране), а затем прокручивает вверх, чтобы увидеть эту ячейку, высота ячейки мала, но отображаются длинные данные (вместо отображения коротких данных). почему это происходит и как решить эту проблему?


person behrad    schedule 23.09.2020    source источник
comment
вместо этого вы можете попробовать selectedRow, если selectedCellIndexPath. И значение selectedRow будет indexPath.row. Надеюсь, это поможет.   -  person Faysal Ahmed    schedule 23.09.2020
comment
вы имеете в виду вместо хранения indexPath сохранить ячейку? Я действительно не понимаю, не могли бы вы объяснить больше?   -  person behrad    schedule 23.09.2020
comment
Не клетка. просто сохраните значение indexPath.row. И в методе heightForRowAt вы можете проверить этот код selectedRow == indexPath.row   -  person Faysal Ahmed    schedule 23.09.2020
comment
да, я могу это сделать, но это не решает мою проблему.   -  person behrad    schedule 23.09.2020


Ответы (1)


Вызов собственной функции для изменения выделенного/невыделенного внешнего вида ячейки НЕ информирует табличное представление об изменении.

С вашим текущим кодом, когда вы второй раз нажимаете на ячейку, вы говорите ячейке изменить свой внешний вид, но, насколько известно табличному представлению, эта ячейка все еще выделена.

Итак, когда вы прокручиваете вниз, а затем делаете резервную копию, табличное представление автоматически повторно выбирает строку.

Измените свой didSelectRowAt на это:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if selectedCellIndexPath == indexPath {
        self.selectedCellIndexPath = nil
        // tell the table view to deselect the row!
        tableView.deselectRow(at: indexPath, animated: true)
        //guard let cell = tableView.cellForRow(at: indexPath) as? SomeCustomCell else { return }
        //cell.deSelected()
    } else {
        self.selectedCellIndexPath = indexPath
    }
    
    tableView.beginUpdates()
    tableView.endUpdates()
    if selectedCellIndexPath != nil {
        // This ensures, that the cell is fully visible once expanded
        tableView.scrollToRow(at: indexPath, at: .none, animated: true)
    }
}
person DonMag    schedule 23.09.2020
comment
Вы знаете, почему tableView не сообщает? Я думаю, что причиной проблемы должны быть beginUpdates и endUpdates. - person behrad; 24.09.2020
comment
@behrad - Дело не в том, что табличное представление не информировано ... Если вы создадите простое тестовое табличное представление, вы увидите, что нажатие на выбранную ячейку не отменяет ее выбор. Ячейка становится невыделенной, когда вы нажимаете (выбираете) другую ячейку. Ваш код вызывал внешний вид отмены выбора ячейки, фактически не отменяя ее. - person DonMag; 24.09.2020
comment
Метод beginUpdates()/endUpdates() не имеет ничего общего с проблемой. - person DonMag; 24.09.2020