自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步
Posted
技术标签:
【中文标题】自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步【英文标题】:UITableView reloadRows() called by action button inside custom UITableViewCell always lags one step behind 【发布时间】:2021-01-16 14:26:15 【问题描述】:我有一个 UITableView 并且我制作了一个自定义单元格视图以在每个单元格内添加一个按钮,该按钮应该在单击时更改其颜色。 尽管数据已正确更新和打印,但视图总是落后一步,即当我单击第一个按钮时,它不会改变颜色,直到我单击下一个按钮。我怀疑 reloadRows() 函数在调用时会导致此问题从 tableview 单元内部。
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)elsefv.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")
【问题讨论】:
【参考方案1】:为您的单元格提供对其控制器的引用是一种不好的模式。
您最好使用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)elseself.fv.insert(indexPath)
self.tbl.reloadRows(at: [indexPath], with: .none)
return cell
现在您不需要单独的func cellMethod(...)
【讨论】:
很遗憾,这并没有解决问题,但感谢您提供的这个漂亮的关闭技巧 嗯...它对我有用。您是否使用了我发布的确切代码? 是的,我做到了..同样的问题发生了..动画更改总是落后一步..我不知道这可能是模拟器问题,但在其他情况下,当我将动作分配给通过在 didSelectRow() 委托函数中使用 reloadRows() 整个单元格它工作正常,但我需要将操作分配给按钮而不是整个单元格 我刚刚在这里找到了一个解决方案,它对我有用:) ***.com/questions/24787098/…,通过向按钮添加操作以强制触发委托函数 (didSelectRowAtIndexPath) 并在委托函数内部应用 reloadRows( )【参考方案2】:我在这里找到了一个解决方案,它对我有用 https://***.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)elseself.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)
【讨论】:
以上是关于自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步的主要内容,如果未能解决你的问题,请参考以下文章
自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步
如何从 UITableViewCell 中的自定义 UIButton 中删除触摸延迟
自定义UITableViewCell中的UITextField意外发现为零
在自定义 UITableViewCell 中按下 UIButton 时如何获取 indexPathForSelectedRow