如何解决UITableView reloadRows() 由自定义 UITableViewCell 内的操作按钮调用总是落后一步
我有一个 UITableView 并且我制作了一个自定义 cellview 来在每个单元格内添加一个按钮,该按钮应该在单击时更改其颜色。 尽管数据已更新并正确打印,但视图总是落后一步,即当我单击第一个按钮时,它不会改变颜色,直到我单击下一个按钮。我怀疑 reloadRows() 函数在调用时会导致此问题从 tableview Cell 内部。
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var mlist = [["1","2","3"],["4","5","6","7","8"],["9","10"],["11","12"],["13","14"]]
var leagues = ["LaLiga","Premier League","Bundesliga","Serie A","Ligue 1"]
var hidden = Set<Int>()
@IBOutlet weak var tbl: UITableView!
var fv = Set<IndexPath>()
func indxs(_ section:Int) -> [IndexPath] {
var indxs = [IndexPath]()
for row in 0..<mlist[section].count {
indxs.append(IndexPath(row: row,section: section))
}
return indxs
}
@objc
private func hideSection(sender: UIButton) {
let section = sender.tag
if hidden.contains(section) {
hidden.remove(section)
tbl.insertRows(at: indxs(section),with: .fade)
}else{
hidden.insert(section)
tbl.deleteRows(at: indxs(section),with: .fade)
}
}
func cellMethod(cell: UITableViewCell) {
guard let i = tbl.indexPath(for: cell) else { return }
if fv.contains(i){fv.remove(i)}else{fv.insert(i)}
tbl.reloadRows(at: [i],with: .none)
}
func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
if hidden.contains(section) {
return 0
}
return mlist[section].count
}
func numberOfSections(in tableView: UITableView) -> Int {
return mlist.count
}
func tableView(_ tableView: UITableView,viewForHeaderInSection section: Int) -> UIView? {
let sectionButton = UIButton()
sectionButton.setTitle(leagues[section],for: .normal)
sectionButton.backgroundColor = .purple
sectionButton.tag = section
sectionButton.addTarget(self,action: #selector(self.hideSection(sender:)),for: .touchUpInside)
return sectionButton
}
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1",for: indexPath) as! mcell
cell.link = self
cell.textLabel?.text = mlist[indexPath.section][indexPath.row]
if fv.contains(indexPath){
cell.accessoryView?.tintColor = .orange
}else{
cell.accessoryView?.tintColor = .gray
}
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
tbl.register(mcell.self,forCellReuseIdentifier: "cell1")
}
}
import UIKit
class mcell: UITableViewCell{
var link:ViewController?
override init(style: UITableViewCell.CellStyle,reuseIdentifier: String?) {
super.init(style: style,reuseIdentifier: reuseIdentifier)
let starButton = UIButton(type: .system)
starButton.setimage(#imageLiteral(resourceName: "fav_star"),for: .normal)
starButton.frame = CGRect(x: 0,y: 0,width: 50,height: 50)
starButton.tintColor = .red
starButton.addTarget(self,action: #selector(handleMarkAsFavorite),for: .touchUpInside)
accessoryView = starButton
}
@objc private func handleMarkAsFavorite() {
print(self.textLabel!.text!)
link?.cellMethod(cell: self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
解决方法
让你的单元格引用它的控制器是一种糟糕的模式。
您最好使用 closure
在您点击星星时让单元格“回调”到控制器。
这是您的单元格类的更新:
class mcell: UITableViewCell{
// "callback" closure to tell the controller that the Star was tapped
var starWasTapped: (() -> ())?
override init(style: UITableViewCell.CellStyle,reuseIdentifier: String?) {
super.init(style: style,reuseIdentifier: reuseIdentifier)
let starButton = UIButton(type: .system)
starButton.setImage(#imageLiteral(resourceName: "fav_star"),for: .normal)
starButton.frame = CGRect(x: 0,y: 0,width: 50,height: 50)
starButton.tintColor = .red
starButton.addTarget(self,action: #selector(handleMarkAsFavorite),for: .touchUpInside)
accessoryView = starButton
}
@objc private func handleMarkAsFavorite() {
print(self.textLabel!.text!)
// tell the controller the Star was tapped
starWasTapped?()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
然后,您的 cellForRowAt
将如下所示:
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1",for: indexPath) as! mcell
cell.textLabel?.text = mlist[indexPath.section][indexPath.row]
if fv.contains(indexPath){
cell.accessoryView?.tintColor = .orange
}else{
cell.accessoryView?.tintColor = .gray
}
// set the cell's "callback" closure
cell.starWasTapped = { [weak self] in
guard let self = self else { return }
if self.fv.contains(indexPath){self.fv.remove(indexPath)}else{self.fv.insert(indexPath)}
self.tbl.reloadRows(at: [indexPath],with: .none)
}
return cell
}
现在您不需要单独的 func cellMethod(...)
我在这里找到了一个解决方案,它对我有用 https://stackoverflow.com/a/39416618/14061160 ,通过向按钮添加动作以强制触发委托函数 (didSelectRowAtIndexPath) 并在委托函数内应用 reloadRows()
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1",for: indexPath) as! mcell
// cell.link = self
cell.textLabel?.text = mlist[indexPath.section][indexPath.row]
if fv.contains(indexPath){
cell.accessoryView?.tintColor = .orange
}else{
cell.accessoryView?.tintColor = .gray
}
cell.starWasTapped = { [weak self] in
guard let self = self else { return }
if self.fv.contains(indexPath){self.fv.remove(indexPath)}else{self.fv.insert(indexPath)}
self.tbl.delegate!.tableView?(self.tbl,didSelectRowAt: indexPath)
}
return cell
}
func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) {
tbl.reloadRows(at: [indexPath],with: .fade)
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。