这是一个问题,当我创建细胞时,我总是处于两难境地。
假设我有一个自定义单元格(PlaceCell
),我在不同的控制器和集合视图中使用它。它有一个标签,用于标识地名(PlaceNameLabel
),并会在用户点按它时导航到详细位置。
这与控制器,集合视图或使用单元格的位置无关,这与使用位置无关。
所以我必须将PlaceNameLabel's UITapGestureRecognizer
代码放在PlaceCell
类中。
class PlaceCell: UICollectionViewCell {
@IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// I have to push a new view controller here
}
}
但是如果我想推送位置细节视图控制器,我需要访问控制器。如果我想访问控制器,我有两个选择,这就是我陷入困境的地方,我已经阅读了大量的SO问题答案,其中大多数建议第二个选项,但我认为第一个是更好的方法。但我不知道引用单元内的控制器是否有问题。
您能否分享您的意见或任何其他方法来处理此问题?
引用单元格内的控制器,
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.controller = self
return cell
}
}
class PlaceCell: UICollectionViewCell {
var controller: UIViewController?
@IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
controller.navigationController.pushViewController(PlaceDetailController(),
animated: true)
}
}
创建协议和委托,将事件传递给控制器并执行您想要的任何操作, (我认为这不太好,因为动作是关于单元格的,我必须多次创建协议功能,因为我在不同的控制器中使用这个单元格)
protocol PlaceCellDelegate {
func handlePlaceNameTouch()
}
class PlaceCell: UICollectionViewCell {
var delegate: PlaceCellDelegate?
@IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
delegate?.handlePlaceNameTouch()
}
}
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.delegate = self
return cell
}
func handlePlaceNameTouch() {
self.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
}
答案 0 :(得分:0)
虽然您可以选择两种方式,但如果您犹豫不决,我会推荐代理方法,因为它更加“快速”#34;这样做的方式,使细胞可重复使用。
这是使用onTapHandler的第三个选项,它不使用委托模式并仍然保持单元格可重用:
class PlaceCell: UICollectionViewCell {
// A handler called when the button is pressed
var onTapHandler: (() -> Void)?
@IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// Make sure the handler exists, else...
guard let handler = self.onTapHandler else {
return
}
// Execute handler
handler()
}
}
然后你会这样使用它:
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.onTapHandler = { [weak self] in
self?.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
return cell
}
}
答案 1 :(得分:0)
您无需专门处理细胞选择。无需使用UITapGestureRecognizer
或无需实施自己的协议来检测单元格选择。
UICollectionView
和UITableView
有自己的协议。
UICollectionView
- UICollectionViewDelegate
协议
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
UITableView
- UITableViewDelegate
协议
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
确认protocol
&在delegate
UIViewController
class viewcontroller : UICollectionViewDelegate {
@IBOutlet weak collectionView: UICollectionView!
func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
}
}
在视图控制器中实现协议方法,我在上面提到过。
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//indexPath - Index path of selected cell.
// Add you cell selection logic here.
}
点击单元格时会触发此方法。在此方法内部从数据源数组中获取模型。并根据用户选择的单元格(模型)导航到详细视图。