从不同于 Cell Click 的 UICollectionViewCell 按钮执行 Segue
Perform Segue from UICollectionViewCell Button different from Cell Click
我有一个 UICollectionViewCell
,还有一个 UIButton
。我有两个不同的动作。第一个,当用户按下单元格时,它将使用 didSelectITemAt
切换到另一个视图;第二个,当用户按下单元格内的 UIButton
时。
我的问题是,在 Swift 代码 MyCollectionViewCell
上,我无法执行 segue,当我编写代码时:
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
它说错误:
Value of Type MyCollectionViewCell has no member performSegue.
我也不会写prepareForSegue
,它不会自动完成。
我如何从一个单元格创建一个 segue,这与单击单元格本身不同?
你不能从你的 UICollectionViewCell
子类中调用 performSegue
,因为 UICollectionViewCell
上有 no interface declared 这样的。
它工作的原因 didSelectItemAtIndexPath()
是因为我认为 delegate of your UICollectionView
is a UIViewController
subclass, what has the function called performSegueWithIdentifier:()`.
您需要在您的 UICollectionViewCell
中单击按钮时通知您的 UIViewController
,因为您有各种可能性,例如 KVO 或使用委托。
这里是一个小代码片段,如何使用 KVO。这个解决方案很棒,只要你不关心按钮是在哪个单元格中按下的。
import UIKit
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var button: UIButton!
}
class CollectionViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
// Add your `UIViewController` subclass, `CollectionViewController`, as the target of the button
// Check out the documentation of addTarget(:) https://developer.apple.com/reference/uikit/uicontrol/1618259-addtarget
cell.button.addTarget(self, action: #selector(buttonTappedInCollectionViewCell), for: .touchUpInside)
return cell
}
func buttonTappedInCollectionViewCell(sender: UIButton) {
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
}
}
编辑:
如果您关心触摸事件发生在哪个单元格中,请使用委托模式。
import UIKit
protocol CollectionViewCellDelegate: class {
// Declare a delegate function holding a reference to `UICollectionViewCell` instance
func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton)
}
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var button: UIButton!
// Add a delegate property to your UICollectionViewCell subclass
weak var delegate: CollectionViewCellDelegate?
@IBAction func buttonTapped(sender: UIButton) {
// Add the resposibility of detecting the button touch to the cell, and call the delegate when it is tapped adding `self` as the `UICollectionViewCell`
self.delegate?.collectionViewCell(self, buttonTapped: button)
}
}
class CollectionViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
// Asssign the delegate to the viewController
cell.delegate = self
return cell
}
}
// Make `CollectionViewController` confrom to the delegate
extension CollectionViewController: CollectionViewCellDelegate {
func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton) {
// You have the cell where the touch event happend, you can get the indexPath like the below
let indexPath = self.collectionView.indexPath(for: cell)
// Call `performSegue`
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
}
}
另一个同样有效的解决方案:
extension YOURViewController : UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOURCell", for: indexPath) as! YOURCollectionViewCell
cell.butTapped = {
[weak self] (YOURCollectionViewCell) -> Void in
// do your actions when button tapped
}
}
return cell
}
class YOURCollectionViewCell: UICollectionViewCell
{
var butQRTapped: ((YOURCollectionViewCell) -> Void)?
@IBAction func deleteButtonTapped(_ sender: AnyObject) {
butTapped?(self)
}
}
这里有一个优雅的解决方案,只需要几行代码:
- 创建自定义 UICollectionViewCell 子类
- 使用故事板,为按钮的“Touch Up Inside”事件定义一个 IBAction
- 定义闭包
- 从 IBAction 调用闭包
Swift 4+ 代码
class MyCustomCell: UICollectionViewCell {
static let reuseIdentifier = "MyCustomCell"
@IBAction func onAddToCartPressed(_ sender: Any) {
addButtonTapAction?()
}
var addButtonTapAction : (()->())?
}
接下来,在
的闭包内实现要执行的逻辑
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCustomCell.reuseIdentifier, for: indexPath) as? MyCustomCell else {
fatalError("Unexpected Index Path")
}
// Configure the cell
// ...
cell.addButtonTapAction = {
// implement your logic here, e.g. call preformSegue()
self.performSegue(withIdentifier: "your segue", sender: self)
}
return cell
}
您也可以将此方法用于 table 视图控制器。
我有一个 UICollectionViewCell
,还有一个 UIButton
。我有两个不同的动作。第一个,当用户按下单元格时,它将使用 didSelectITemAt
切换到另一个视图;第二个,当用户按下单元格内的 UIButton
时。
我的问题是,在 Swift 代码 MyCollectionViewCell
上,我无法执行 segue,当我编写代码时:
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
它说错误:
Value of Type MyCollectionViewCell has no member performSegue.
我也不会写prepareForSegue
,它不会自动完成。
我如何从一个单元格创建一个 segue,这与单击单元格本身不同?
你不能从你的 UICollectionViewCell
子类中调用 performSegue
,因为 UICollectionViewCell
上有 no interface declared 这样的。
它工作的原因 didSelectItemAtIndexPath()
是因为我认为 delegate of your UICollectionView
is a UIViewController
subclass, what has the function called performSegueWithIdentifier:()`.
您需要在您的 UICollectionViewCell
中单击按钮时通知您的 UIViewController
,因为您有各种可能性,例如 KVO 或使用委托。
这里是一个小代码片段,如何使用 KVO。这个解决方案很棒,只要你不关心按钮是在哪个单元格中按下的。
import UIKit
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var button: UIButton!
}
class CollectionViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
// Add your `UIViewController` subclass, `CollectionViewController`, as the target of the button
// Check out the documentation of addTarget(:) https://developer.apple.com/reference/uikit/uicontrol/1618259-addtarget
cell.button.addTarget(self, action: #selector(buttonTappedInCollectionViewCell), for: .touchUpInside)
return cell
}
func buttonTappedInCollectionViewCell(sender: UIButton) {
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
}
}
编辑: 如果您关心触摸事件发生在哪个单元格中,请使用委托模式。
import UIKit
protocol CollectionViewCellDelegate: class {
// Declare a delegate function holding a reference to `UICollectionViewCell` instance
func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton)
}
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var button: UIButton!
// Add a delegate property to your UICollectionViewCell subclass
weak var delegate: CollectionViewCellDelegate?
@IBAction func buttonTapped(sender: UIButton) {
// Add the resposibility of detecting the button touch to the cell, and call the delegate when it is tapped adding `self` as the `UICollectionViewCell`
self.delegate?.collectionViewCell(self, buttonTapped: button)
}
}
class CollectionViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
// Asssign the delegate to the viewController
cell.delegate = self
return cell
}
}
// Make `CollectionViewController` confrom to the delegate
extension CollectionViewController: CollectionViewCellDelegate {
func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton) {
// You have the cell where the touch event happend, you can get the indexPath like the below
let indexPath = self.collectionView.indexPath(for: cell)
// Call `performSegue`
self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
}
}
另一个同样有效的解决方案:
extension YOURViewController : UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOURCell", for: indexPath) as! YOURCollectionViewCell
cell.butTapped = {
[weak self] (YOURCollectionViewCell) -> Void in
// do your actions when button tapped
}
}
return cell
}
class YOURCollectionViewCell: UICollectionViewCell
{
var butQRTapped: ((YOURCollectionViewCell) -> Void)?
@IBAction func deleteButtonTapped(_ sender: AnyObject) {
butTapped?(self)
}
}
这里有一个优雅的解决方案,只需要几行代码:
- 创建自定义 UICollectionViewCell 子类
- 使用故事板,为按钮的“Touch Up Inside”事件定义一个 IBAction
- 定义闭包
- 从 IBAction 调用闭包
Swift 4+ 代码
class MyCustomCell: UICollectionViewCell {
static let reuseIdentifier = "MyCustomCell"
@IBAction func onAddToCartPressed(_ sender: Any) {
addButtonTapAction?()
}
var addButtonTapAction : (()->())?
}
接下来,在
的闭包内实现要执行的逻辑override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCustomCell.reuseIdentifier, for: indexPath) as? MyCustomCell else {
fatalError("Unexpected Index Path")
}
// Configure the cell
// ...
cell.addButtonTapAction = {
// implement your logic here, e.g. call preformSegue()
self.performSegue(withIdentifier: "your segue", sender: self)
}
return cell
}
您也可以将此方法用于 table 视图控制器。