Reputation: 590
I'm successfully using a protocol and delegate method to trigger an action from a button within a UICollectionViewCell.
I want to re-use this custom cell on the same view controller (first UICollectionView - set of items, then the second one on the same VC is a filtered set of different items, but using the same custom cell layout).
All is going fine, except the delegate method (which returns a reference to the cell in which the button was clicked) crashes because it doesn't know which UICollectionView the button was passed in from.
In the custom Cell:
protocol BookmarkButton {
func onClickBookmarkButton(cell: RecommendedChallengeCollectionViewCell)
}
@IBAction func bookmarkButtonPressed(_ sender: Any) {
print("bookmark button pressed")
cellDelegate?.onClickBookmarkButton(cell: self)
}
In the main View Controller:
extension DiscoveryViewController: BookmarkButton {
func onClickBookmarkButton(cell: RecommendedChallengeCollectionViewCell) {
let indexPath : IndexPath = recommendedCollectionView.indexPath(for: cell)!
The above works fine when I have a single CollectionView using the custom cell with the delegate. However, I can't figure out how to either change what is passed when coming from the cell OR get the collection view from the cell so that I can execute the right path.
Help appreciated!
Edit 1: adding cellForItemAt per request I've got two UICollectionViews in the view controller - both using the same custom cell...set by the below:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == recommendedCollectionView {
let cell = recommendedCollectionView.dequeueReusableCell(withReuseIdentifier: "recommendedChallengeCell", for: indexPath) as! RecommendedChallengeCollectionViewCell
} else {
let cell = newCollectionView.dequeueReusableCell(withReuseIdentifier: "recommendedChallengeCell", for: indexPath) as! RecommendedChallengeCollectionViewCell
Edit 2: An approach that I got to work, but seems clunky - wondering if there is a better way to approach it?
With this solution, I have to go through all CollectionViews within the view controller (that are delegates of the button) to see which one isn't nil. I'm guessing there may be a better approach.
extension DiscoveryViewController: BookmarkButton {
func onClickBookmarkButton(cell: RecommendedChallengeCollectionViewCell) {
var indexPath : IndexPath?
//check to see which collectionview.indexPath(for: cell) isn't nil
if recommendedCollectionView.indexPath(for: cell) != nil {
indexPath = recommendedCollectionView.indexPath(for: cell)
} else if newCollectionView.indexPath(for: cell) != nil {
indexPath = newCollectionView.indexPath(for: cell)
}
Upvotes: 0
Views: 112
Reputation: 513
I think you can create collectionViewType
on CustomCell
like CustomCel.collectionViewType = <view type>
may be string, enum, ... and on cellForItemAt
just set collectionViewType
for cell. So after that you can check and using exactly CollectionView when delegate return cell.
Help this idea can help.
Upvotes: 0
Reputation: 5073
Defining a delegate for the cell is overkill. Add a closure to the cell and then call it from cellForItemAt
. From there you have access to the cell and both collectionViews.
class RecommendedChallengeCollectionViewCell: UICollectionViewCell {
var onClickBookmarkButton: (() -> Void)?
@IBAction func onButtonClick(_ sender: UIButton) {
onClickBookmarkButton?()
}
}
class DiscoveryViewController: UIViewController {
@IBOutlet weak var recommendedCollectionView: UICollectionView!
@IBOutlet weak var newCollectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == recommendedCollectionView {
let cell = recommendedCollectionView.dequeueReusableCell(
withReuseIdentifier: "recommendedChallengeCell",
for: indexPath
) as! RecommendedChallengeCollectionViewCell
cell.onClickBookmarkButton = { [unowned self] in
guard let indexPath = self.recommendedCollectionView.indexPath(for: cell) else { return }
self.handleButtonClick(at: indexPath, in: self.recommendedCollectionView)
}
return cell
} else {
let cell = newCollectionView.dequeueReusableCell(
withReuseIdentifier: "recommendedChallengeCell",
for: indexPath
) as! RecommendedChallengeCollectionViewCell
cell.onClickBookmarkButton = { [unowned self] in
guard let indexPath = self.newCollectionView.indexPath(for: cell) else { return }
self.handleButtonClick(at: indexPath, in: self.newCollectionView)
}
return cell
}
}
func handleButtonClick(at indexPath: IndexPath, in collectionView: UICollectionView) {
// ...
}
}
Upvotes: 1