UICollectionViewCell 与它的 UICollectionViewController 对话
UICollectionViewCell Talking to Its UICollectionViewController
虽然可能是主观的,但我想知道如何去拥有一个自定义 UICollectionViewCell
,当它的 UIButton
被按下时,通知自定义 UICollectionViewController
要做什么。
我的第一个想法是在 CustomCell
中使用 delegate
,如下所示:
class CustomCell: UICollectionViewCell {
var delegate: CustomCellDelegate?
static let reuseIdentifier = "CustomCell"
@IBOutlet weak private var button: UIButton! {
didSet {
button.addTarget(self, action: #selector(self.toggleButton), for: .touchUpInside)
}
}
@objc private func toggleButton() {
delegate?.didToggleButton()
}
}
其中 CustomCellDelegate
的 class 协议定义为:
protocol CustomCellDelegate: class {
func didToggleButton()
}
然后UICollectionViewController
实现了didToggleButton
函数并将自己作为delegate
分配给每个单元格如下:
class CustomCollectionViewController: UICollectionViewController, CustomCellDelegate {
func didToggleButton() {
// do some stuff and then update the cells accordingly ...
collectionView?.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let customCell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCell.reuseIdentifier, for: indexPath) as? CustomCell else { fatalError("Unexpected indexPath") }
customCell.delegate = self
return customCell
}
}
这是解决此问题的正确方法吗,还是有另一种方法可以在 UICollectionViewCell
与其父控制器之间进行通信?
感谢您的任何建议。
是的,当通信必须只与一个 object 进行时,委托是最佳选择。在这种情况下 parent UICollectionViewController
其他通信方式是-
通知:当我们想要传达多个 objects post 通知时。
KVO:了解 value/property 何时更改。但请谨慎使用。
是的,这确实是正确的解决方案。您的自定义单元是盲目的,它们对您的控制器一无所知。他们只触发委托方法。
但是,还有一个更正确的解决方案,那就是观察。有人喜欢授权,有人喜欢观察。您可以使用 NotificationCenter
到 post 关于单元格中发生的触摸的通知,并使您的控制器成为对这些通知做出反应的观察者。
// inside your cell
NotificationCenter.default.post(name: Notification.Name("ButtonPressed"), object: nil)
// inside your controller
NotificationCenter.default.addObserver(self, selector: #selector(someHandler), name: Notification.Name("ButtonPressed"), object: nil)
你的 func someHandler()
将在你的控制器(观察者)捕获到 posted 事件时处理调用。
此外,还有 KVO,但它很乱而且不适合那种特殊情况,因为你有多个单元格。
设置通信通道的另一种方法是绑定。它既可以是手动编写的,也可以是反应式的(例如,使用 ReactiveSwift)。
例如手动一:
// in your controller
cell.pressHandler = {
// do something
...
}
// in your cell
var pressHandler: (() -> Void)?
...
// when the button is pressed you execute that handler
pressHandler?()
虽然可能是主观的,但我想知道如何去拥有一个自定义 UICollectionViewCell
,当它的 UIButton
被按下时,通知自定义 UICollectionViewController
要做什么。
我的第一个想法是在 CustomCell
中使用 delegate
,如下所示:
class CustomCell: UICollectionViewCell {
var delegate: CustomCellDelegate?
static let reuseIdentifier = "CustomCell"
@IBOutlet weak private var button: UIButton! {
didSet {
button.addTarget(self, action: #selector(self.toggleButton), for: .touchUpInside)
}
}
@objc private func toggleButton() {
delegate?.didToggleButton()
}
}
其中 CustomCellDelegate
的 class 协议定义为:
protocol CustomCellDelegate: class {
func didToggleButton()
}
然后UICollectionViewController
实现了didToggleButton
函数并将自己作为delegate
分配给每个单元格如下:
class CustomCollectionViewController: UICollectionViewController, CustomCellDelegate {
func didToggleButton() {
// do some stuff and then update the cells accordingly ...
collectionView?.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let customCell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCell.reuseIdentifier, for: indexPath) as? CustomCell else { fatalError("Unexpected indexPath") }
customCell.delegate = self
return customCell
}
}
这是解决此问题的正确方法吗,还是有另一种方法可以在 UICollectionViewCell
与其父控制器之间进行通信?
感谢您的任何建议。
是的,当通信必须只与一个 object 进行时,委托是最佳选择。在这种情况下 parent UICollectionViewController
其他通信方式是-
通知:当我们想要传达多个 objects post 通知时。
KVO:了解 value/property 何时更改。但请谨慎使用。
是的,这确实是正确的解决方案。您的自定义单元是盲目的,它们对您的控制器一无所知。他们只触发委托方法。
但是,还有一个更正确的解决方案,那就是观察。有人喜欢授权,有人喜欢观察。您可以使用 NotificationCenter
到 post 关于单元格中发生的触摸的通知,并使您的控制器成为对这些通知做出反应的观察者。
// inside your cell
NotificationCenter.default.post(name: Notification.Name("ButtonPressed"), object: nil)
// inside your controller
NotificationCenter.default.addObserver(self, selector: #selector(someHandler), name: Notification.Name("ButtonPressed"), object: nil)
你的 func someHandler()
将在你的控制器(观察者)捕获到 posted 事件时处理调用。
此外,还有 KVO,但它很乱而且不适合那种特殊情况,因为你有多个单元格。
设置通信通道的另一种方法是绑定。它既可以是手动编写的,也可以是反应式的(例如,使用 ReactiveSwift)。
例如手动一:
// in your controller
cell.pressHandler = {
// do something
...
}
// in your cell
var pressHandler: (() -> Void)?
...
// when the button is pressed you execute that handler
pressHandler?()