У меня есть UITableView, который я использую для отображения массива настраиваемых объектов. Каждый объект имеет несколько свойств, включая логическое свойство, которое указывает, является ли этот элемент новым или нет.
Мое представление содержимого UITableViewCell определено в раскадровке и имеет начальный макет, подобный этому:
В моем UITableViewController, когда я удаляю свои ячейки из очереди, я вызываю на моем UITableViewCell метод, который настраивает данные, которые будут отображаться в ячейке, прежде чем я верну их. Одно из свойств, которое я проверяю, - это свойство .isNew, о котором я упоминал ранее. Если это значение истинно, то я создаю UIButton и вставляю его в качестве подпредставления в представление содержимого ячейки, поэтому я получаю что-то вроде этого:
Просто для контекста, эта кнопка покажет «новое» изображение, чтобы указать, что этот элемент является новым. Я также подключаю метод, который срабатывает при нажатии кнопки. Этот метод также определен в моем UITableViewCell и выглядит так:
@objc func newIndicatorButtonTapped(sender: UIButton!) {
// call delegate method and pass this cell as the argument
delegate?.newIndicatorButtonTapped(cell: self)
}
Я также создал протокол, который определяет метод делегата. Мой UITableViewController соответствует этому, и я вижу, что этот код срабатывает, когда я нажимаю кнопку в своей ячейке (ах). Вот метод делегата (определенный в расширении на моем UITableViewController):
func newIndicatorButtonTapped(cell: UITableViewCell) {
if let indexPath = self.tableView.indexPath(for: cell) {
print(indexPath.row)
}
}
Я вижу, что строка из indexPath правильно распечатывается в Xcode, когда я нажимаю на ячейку. Когда мой пользователь нажимает на эту кнопку, мне нужно удалить ее (кнопку) и обновить ограничение для моего UILabel, чтобы оно снова выровнялось с передним краем представления содержимого, как показано в первом макете выше. К сожалению, у меня, похоже, возникла проблема с переработкой ячеек, потому что UIButton исчезает и снова появляется в разных ячейках, когда я прокручиваю их. Нужно ли мне сбрасывать компоновку / внешний вид ячейки, прежде чем она будет переработана, или я что-то неправильно понимаю в том, как работает переработка элементов? Любые советы будут очень признательны!





Вы можете подумать, что получаете «свежую» ячейку, но когда ячейка получает повторно использованный, это означает, что она получает повторно использованный.
В этом очень легко убедиться, изменив цвет текста базовой ячейки.
Например:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyID", for: indexPath) as! MyCustomCell
if indexPath.row == 3 {
cell.theLabel.textColor = .red
}
return cell
}
Как и следовало ожидать, при первой загрузке таблицы цвет текста для 4-й строки изменится (индексирование строк начинается с нуля).
Однако предположим, что у вас есть 100 строк? По мере прокрутки ячейки будут иметь вид повторно использованный ... и каждый раз, когда эта исходная 4-я ячейка будет повторно использоваться, в ней все равно будет отображаться красный текст.
Итак, как вы догадались, да ... вам нужно «сбрасывать» свою ячейку до ее исходного макета / содержимого / цветов / и т. д. Каждый раз, когда вы хотите ее использовать:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyID", for: indexPath) as! MyCustomCell
if indexPath.row == 3 {
cell.theLabel.textColor = .red
} else {
cell.theLabel.textColor = .black
}
return cell
}
Возможно, вы захотите скрыть кнопку, а затем изменить макет при ее нажатии.
Запуск действия из ячейки в tableView с помощью протокола, а затем сброс макета при повторном использовании ячейки - хороший способ сделать это.
Выполнение этого в полностью программной ячейке будет таким:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
cell.isNew = indexPath.row == 0 ? true : false
cell.layoutIfNeeded()
return cell
}
И класс ячейки должен быть похож на: (вы можете делать то, что вам нужно, изменяя ограничение Autolayout, напрямую манипулируя фреймом или используя UIStackView)
class Cell: UITableViewCell {
var isNew: Bool = false {
didSet {
if isNew {
button.isHidden = true
leftConstraint.constant = 20
} else {
button.isHidden = false
leftConstraint.constant = 100
}
self.setNeedsLayout()
}
}
var button: UIButton!
var label: UILabel!
var leftConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button = UIButton(type: .system)
button.setTitle("Click", for: .normal)
self.contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 50).isActive = true
button.heightAnchor.constraint(equalToConstant: 10).isActive = true
button.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 20).isActive = true
button.topAnchor.constraint(equalTo: self.topAnchor, constant: 20).isActive = true
label = UILabel()
label.text = "Label"
self.contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.widthAnchor.constraint(equalToConstant: 200).isActive = true
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
label.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
leftConstraint = label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 100)
leftConstraint.isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}