0

I have a UICollectionView that appropriately recognizes taps on its cells in its collectionView(didSelectItemAt: ) delegate method.

However, I then embedded a collection view within the cell itself (so that each cell has its own collection view inside of it), but now the parent cell is not recognizing any taps anymore, I'm assuming because the embedded collection view is eating them up.

Is there some property that needs to be set so that the original (parent) cells register taps again even with their embedded collection views?

Eric
  • 569
  • 4
  • 21

2 Answers2

1

This functionality can be confusing, as users are accustomed to "something else" happening when interacting with a control in a table view cell, rather than it selecting (or also selecting) the row itself.

However, if you really want to do that...

One approach is to use a closure in your cell. When you handle didSelectItemAt use the closure to tell the table view controller to select the row.

Note that Apple's docs point out:

Note

Selecting a row programmatically doesn't call the delegate methods tableView(_:willSelectRowAt:) or tableView(_:didSelectRowAt:), nor does it send selectionDidChangeNotification notifications to observers.

So, if you need to execute code when a table view row is selected, you'll need to call that yourself - something like this:

func myTableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("My didSelectRowAt:", indexPath)
}

Using the code in my answer to your previous question...

In SomeTableCell add this closure setup:

public var didSelectClosure: ((UITableViewCell) ->())?

and, still in SomeTableCell:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print("collectionView didSelecteItemAt:", indexPath)
    print("Calling closure...")
    didSelectClosure?(self)
}

Next, in cellForRowAt in the table view controller, set the closure:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "someTableCell", for: indexPath) as! SomeTableCell
    cell.rowTitleLabel.text = "Row \(indexPath.row)"
    cell.thisData = myData[indexPath.row]
    
    cell.didSelectClosure = { [weak self] c in
        guard let self = self,
              let idx = tableView.indexPath(for: c)
        else { return }
        // select the row
        tableView.selectRow(at: idx, animated: true, scrollPosition: .none)
        // that does not call didSelectRowAt, so call our own func
        //   if we want something to happen on row selection
        self.myTableView(tableView, didSelectRowAt: idx)
    }
    
    return cell
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • I appreciate the response. Unfortunately, in my case this won't fully work because my child collection view cells don't take up the full space of the child collection view. So there's a lot of empty "child collection view" space that will not be able to register any taps. Could I maybe put a button in my parent cell that covers the child collection view entirely? The only problem is that I need to be able to horizontal scroll in the child collection view still. It's a dilemma. Maybe another approach like you said would just be best. – Eric Apr 28 '22 at 00:59
  • @Eric - I guess I'm confused by *"... there's a lot of empty "child collection view" space ..."* -- change your cell layout do there's no "empty space"? Add a tap gesture to the "empty space"? Track touches began/ended? Maybe re-evaluate your UI - would a multi-section collection view work better? Would a compositional layout work better? Perhaps if you provide a little more detail about your layout and what you're actually trying to do... – DonMag Apr 28 '22 at 02:14
0

you can implement UICollectionViewDataSource & UICollectionViewDelegate methods of inner collectionViews inside the cells itself & pass the events with closure to main class with main UICollectionView.

Mohsen m
  • 11
  • 3