gpt4 book ai didi

ios - UITableView 自定义单元格在滚动时复制 UIButton

转载 作者:可可西里 更新时间:2023-11-01 01:51:50 25 4
gpt4 key购买 nike

我有一个 UITableViewController,其中包含许多自定义 UITableViewCells 类型。

其中一种类型就是包含 UIStackView 的单元格,该单元格本身包含一个或多个 UIButton

当滚动屏幕并重新打开时,将再次添加按钮。这发生在每个滚动事件上。

Pre Scroll Image Post Scroll Image

我了解,由于单元被重复用于性能,可能正在发生的是我在 cellForRowAt 中配置单元的设置代码再次执行。

因此,它将数据源中的 3 个按钮添加到单元格中,该单元格已包含上次渲染中的按钮。

我不明白如何解决这个问题并防止这种行为,非常感谢有人在我迷路时提供见解。

我已经能够准备一个小应用程序来重新创建它,因为我无法共享我当前的项目,因为它是封闭源代码。

对于下面堆积如山的代码,我深表歉意,但这只是简单地投入一个项目并重新创建所需的最低要求。

class TableViewController: UITableViewController {

let textCellId = "textCellId"
let buttonCellId = "buttonCellId"

// MARK: - Mock Data Source

let cellContent = [
Message(type: .buttonGroup, buttonGroup: [
MessageButton(label: "Button #1"),
MessageButton(label: "Button #2"),
MessageButton(label: "Button #3")
]),
Message(type: .text, text: "A"),
Message(type: .text, text: "B"),
Message(type: .text, text: "C"),
Message(type: .text, text: "D"),
Message(type: .text, text: "E"),
Message(type: .text, text: "F"),
Message(type: .text, text: "G"),
Message(type: .text, text: "H"),
Message(type: .text, text: "I"),
Message(type: .text, text: "J"),
Message(type: .text, text: "K"),
Message(type: .text, text: "L"),
Message(type: .text, text: "M"),
Message(type: .text, text: "N"),
Message(type: .text, text: "O"),
Message(type: .text, text: "P"),
Message(type: .text, text: "Q"),
Message(type: .text, text: "R"),
Message(type: .text, text: "S"),
]

override func viewDidLoad() {
super.viewDidLoad()

registerCells()
configureTableView()
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellContent.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = cellContent[indexPath.row]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: buttonCellId, for: indexPath) as! ButtonCell
cell.buttonGroupContent = item.buttonGroup
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: textCellId, for: indexPath) as! TextCell
cell.textLabel?.text = item.text
return cell
}
}
}

// MARK: - Misc TableView Setup

extension TableViewController {

fileprivate func registerCells() {
tableView.register(TextCell.self, forCellReuseIdentifier: textCellId)
tableView.register(ButtonCell.self, forCellReuseIdentifier: buttonCellId)
}

fileprivate func configureTableView() {
tableView.allowsSelection = false
tableView.alwaysBounceVertical = false
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200
tableView.separatorStyle = .none
tableView.backgroundColor = UIColor.lightGray
tableView.contentInset = UIEdgeInsets(top: 24, left: 0, bottom: 50, right: 0)
tableView.tableFooterView = UIView()
}
}

// MARK: - Cell Types

class TextCell: UITableViewCell {

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}


class ButtonCell: UITableViewCell {

var buttonGroupContent: [MessageButton]? {
didSet {
anchorSubViews()
}
}

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

fileprivate var button: UIButton {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.darkGray
button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
button.layer.cornerRadius = 5
button.layer.masksToBounds = true
return button
}

fileprivate let buttonGroupStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
stackView.isLayoutMarginsRelativeArrangement = true
stackView.spacing = UIStackView.spacingUseSystem
return stackView
}()
}

extension ButtonCell {
fileprivate func anchorSubViews() {
guard let buttons = buttonGroupContent?.enumerated() else { return }

for (index, b) in buttons {
let btn = button
btn.setTitle(b.label, for: .normal)
btn.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
btn.tag = index
buttonGroupStackView.addArrangedSubview(btn)
}

addSubview(buttonGroupStackView)

NSLayoutConstraint.activate([
buttonGroupStackView.topAnchor.constraint(equalTo: topAnchor),
buttonGroupStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
buttonGroupStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
buttonGroupStackView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}
}





// MARK: - Misc for setup

struct MessageButton {
let label: String
}

enum MessageType {
case text, buttonGroup
}

struct Message {
let type: MessageType
let text: String?
let buttonGroup: [MessageButton]?

init(type: MessageType, text: String? = nil, buttonGroup: [MessageButton]? = nil) {
self.type = type
self.text = text
self.buttonGroup = buttonGroup
}
}

最佳答案

因为单元格是可重复使用的,所以内容会保留下来。因此,您的旧按钮仍在您的堆栈 View 中,并且您每次都在添加下一个按钮。

要解决此问题,请在向 UIStackView 添加新按钮之前删除旧按钮

extension ButtonCell {

fileprivate func anchorSubViews() {
...

for case let button as UIButton in buttonGroupStackView.subviews {
button.removeFromSuperview()
}

for (index, b) in buttons {
...
buttonGroupStackView.addArrangedSubview(btn)
}
...
}
}

关于ios - UITableView 自定义单元格在滚动时复制 UIButton,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54026928/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com