英文:
UIAction calling multiple times when tapped on UIButton in CollectionViewCell
问题
当我点击按钮时,它会触发多次。
CollectionViewCell 文件代码
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
}
ViewController - cellForItemAt 方法实现
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.deleteButton.addAction(action, for: .touchUpInside)
return cell
}
如果我配置 UIButton 的 addTarget,那么它可以正常工作,但我不确定为什么使用 addAction 就不起作用。
英文:
When I tap on button it will trigger multiple times.
CollectionViewCell file code
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
}
ViewController - cellforItemAt method implementation
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.deleteButton.addAction(action, for: .touchUpInside)
return cell
}
If I configure UIButton addTarget then it work fine but I am not sure why it's not working with addAction.
答案1
得分: 1
因为UICollectionView
重用了一些PhotoCell
的实例,所以动作被触发了多次。这意味着通过dequeueReusableCell()
返回的PhotoCell
的deleteButton
可能已经添加了动作,并且最终会为相同的事件具有多个动作。
一个可能的解决方案是在PhotoCell
中覆盖prepareForReuse()
方法,在那里移除动作。
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
var actions: [(UIAction, UIControl.Event)] = []
func addAction(_ action: UIAction, for event: UIControl.Event) {
self.actions.append((action, event))
self.deleteButton.addAction(action, for: event)
}
override func prepareForReuse() {
super.prepareForReuse()
for tuple in self.actions {
self.deleteButton.removeAction(tuple.0, for: tuple.1)
}
self.actions = []
}
}
在使用上述代码时,在函数func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
中,需要在cell
上调用addAction
,而不是在cell.deleteButton
上调用:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.addAction(action, for: .touchUpInside)
return cell
}
英文:
The actions get triggered multiple times because some instances of PhotoCell
are reused by the UICollectionView
. This means that the deleteButton
of the PhotoCell
returned by dequeueReusableCell()
may already have actions added to it and will eventually possess multiple actions for the same events.
One possible solution is to override prepareForReuse()
in PhotoCell
and remove the actions there.
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
var actions: [(UIAction, UIControl.Event)] = []
func addAction(_ action: UIAction, for event: UIControl.Event) {
self.actions.append((action, event))
self.deleteButton.addAction(action, for: event)
}
override func prepareForReuse() {
super.prepareForReuse()
for tuple in self.actions {
self.deleteButton.removeAction(tuple.0, for: tuple.1)
}
self.actions = []
}
}
When using the above code addAction
needs to be called on cell
instead of cell.deleteButton
in the function func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.addAction(action, for: .touchUpInside)
return cell
}
答案2
得分: 1
一个可能的解决方案是在PhotoCell
中覆盖prepareForReuse()
方法,就像Johann
所提到的那样。
> prepareForReuse()
用于执行任何必要的清理工作,以便为视图重新使用做准备。
我们可以在那里从按钮中移除所有事件!
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
override func prepareForReuse() {
super.prepareForReuse()
self.deleteButton.removeTarget(nil, action: nil, for: .allEvents)
}
}
在func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
中像通常一样添加动作。
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.deleteButton.addAction(action, for: .touchUpInside)
return cell
}
英文:
One possible solution is to override prepareForReuse()
in PhotoCell
, as Johann
mentioned.
> preparaForReuse()
is use to Performs any clean up necessary to
> prepare the view for use again.
We can remove all events from the button there!
class PhotoCell: UICollectionViewCell {
@IBOutlet weak var deleteButton: UIButton!
override func prepareForReuse() {
super.prepareForReuse()
self.deleteButton.removeTarget(nil, action: nil, for: .allEvents)
}
}
Add action in func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
like normally we do.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCell else { return UICollectionViewCell() }
let action = UIAction { _ in
print("Delete button tapped!!!", indexPath.row)
}
cell.deleteButton.addAction(action, for: .touchUpInside)
return cell
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论