2017-08-16 70 views
2

我有一個自定義的UICollectionViewCell,裏面有一個按鈕。當我點擊按鈕時,會在該子類中觸發一個事件。然後我想在UICollectionView本身觸發一個事件,我可以在視圖控制器中處理這個事件。從UICollectionViewCell傳播自定義事件

僞代碼:

class MyCell : UICollectionViewCell { 
    @IBAction func myButton_touchUpInside(_ sender: UIButton) { 
     // Do stuff, then propagate an event to the UICollectionView 
     Event.fire("cellUpdated") 
    } 
} 

class MyViewController : UIViewController { 
    @IBAction func collectionView_cellUpdated(_ sender: UICollectionView) { 
     // Update stuff in the view controller 
     // to reflect changes made in the collection view 
    } 
} 

理想情況下,我確定會一起出現在界面生成器的默認操作網點,讓我然後將其拖到我的視圖控制器代碼來創建上述collectionView_cellUpdated函數的事件,類似於@IBInspectable在公開自定義屬性時的工作方式。

有沒有什麼辦法可以在Swift 3中實現這樣的模式?或者,如果沒有,任何使它成爲可能的庫?

回答

1

我不完全理解你的問題,但是從我得到了什麼,你可以簡單地用一個closure傳遞UIButton敲擊事件回UIViewController

例子:

1.定製UICollectionViewCell

class MyCell: UICollectionViewCell 
{ 
    var tapHandler: (()->())? 

    @IBAction func myButton_touchUpInside(_ sender: UIButton) 
    { 
     tapHandler?() 
    } 
} 

2. MyViewController

class MyViewController: UIViewController, UICollectionViewDataSource 
{ 
    //YOUR CODE.. 

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell 
     cell.tapHandler = { 
      //Here you can do your custom handling 
     } 
     return cell 
    } 
} 

讓我知道,如果你面對任何問題。

+0

嗯,這可能也會起作用。我沒有想過以這種方式使用閉包。 – Extragorey

+0

閉包實際上比委託模式更簡單易用。 – PGDev

1

做的最好的事情就是讓自定義協議爲自定義單元格類

protocol CustomCellProtocolDelegate { 
    func custom(cell: YourCellClass, hadButton: UIButton, pressedWithInfo : [String:Any]?) 
} 

使這個細胞類有這個協議作爲一種特殊的委託,並觸發該委託:

class YourCellClass: UICollectionViewCell { 

    var delegate : CustomCellProtocolDelegate? 

    var indexPath : IndexPath? //Good practice here to have an indexPath parameter 

    var yourButton = UIButton() 

    init(frame: CGRect) { 
     super.init(frame: frame) 
     yourButton.addTarget(self, selector: #selector(triggerButton(sender:))) 
    } 
    func triggerButton(sender: UIButton) { 
     if let d = self.delegate { 
     d.custom(cell: self, hadButton: sender, pressedWithInfo : /*Add info if you want*/) 
     } 
    } 

} 

在您的控制器中,您將其與代理人相符,並將代理人應用於cellForItem: atIndexPath中的每個單元格:

class YourControllerThatHasTheCollectionView : UIViewController, CustomCellProtocolDelegate { 

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath) as! YourCellClass 
     cell.delegate = self 
     cell.indexPath = indexPath 
     return cell 
    } 

    func custom(cell: YourCellClass, hadButton: UIButton, pressedWithInfo : [String:Any]?) { 

     //Here you can process which button was selected, etc.. and apply your changes to your collectionview 

    } 

} 

最佳做法是在pressedWithInfo內的委託方法中傳遞單元格的indexPath參數。它爲您節省了計算實際被按下的單元格的麻煩;因此我通常爲每個UICollectionViewCell子類添加一個indexPath元素。更重要的是,包括協議方法裏面的指標:

protocol CustomCellProtocolDelegate { 
     func custom(cell: YourCellClass, hadButton: UIButton, pressedAt: IndexPath, withInfo : [String:Any]?) 
    } 

    func triggerButton(sender: UIButton) { 
     if let d = self.delegate { 
      d.custom(cell: self, hadButton: sender, pressedAt: indexPath!, withInfo : /*Add info if you want*/) 
     } 
    } 
+0

謝謝,這讓我做我想做的事情。不過,我仍然很好奇是否可以將自定義事件公開給Interface Builder。 – Extragorey

+0

有趣的是,我還沒有找到方法。但是,它可能是,可能的。由於動作/可執行類型'(() - >())'可以是一個類的參數,它在技術上可以被IB檢測到。但是在我的測試中,這似乎不是這種情況。將繼續尋找 – murphguy