Search code examples
swiftcollectionview

Cannot get indexPath and selection on Collection View


I'm facing a problem with my collection view. I'm trying to pick the indexPath of an item to show more info on it after the tap, but I can't get it and figure out why.

I tried to allows collection View selection, but nothing happened. I also tried to add a tap gesture on the cell, but don't know how to get the indexPath from there. I add the same code on another VC, where the collection view is on the entire screen, and it works ( here, the collection View is half the screen ).

Here is the (updated) code for the collection View :

class SearchRunnerVC: UIViewController {

    //MARK: - Objects
    var lastNameTextField       = RSTextField(placeholder: "Nom du coureur", returnKeyType: .next,
                                              keyboardType: .default)
    var firstNameTextField      = RSTextField(placeholder: "Prénom", returnKeyType: .next,
                                              keyboardType: .default)
    var numberTextField         = RSTextField(placeholder: "Numéro de dossard", returnKeyType: .next,
                                              keyboardType: .numberPad)
    var raceTextField           = RSTextField(placeholder: "Course", returnKeyType: .done,
                                              keyboardType: .default)

    var searchButton            = RSButton(backgroundColor: .systemPink, title: "Rechercher")
    var collectionView          : UICollectionView! = nil

    var emptyLabel              = UILabel()

    let hud = JGProgressHUD(style: .dark)

    lazy var textFields         = [lastNameTextField, firstNameTextField, numberTextField, raceTextField]

    //MARK: - Properties
    let padding = CGFloat(20)
    let runnersCollection = Firestore.firestore().collection("Runner")
    var runners = [Runner]()

    //MARK: - Lifecycle Methods
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.navigationBar.prefersLargeTitles = true
        title = "Rechercher"
    }
}
extension SearchRunnerVC {
    fileprivate func setupUI() {
        configureSuperView()
        configureTextFields()
        configureCollectionView()
        configureButton()
        configureConstraints()
    }

    fileprivate func configureSuperView() {
        view.backgroundColor = .systemBackground
        let viewTap = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard(_:)))
        view.addGestureRecognizer(viewTap)
    }
    fileprivate func configureConstraints() {
        for textField in textFields {
            view.addSubview(textField)

            textField.leftToSuperview(view.leftAnchor, offset: padding)
            textField.rightToSuperview(view.rightAnchor, offset: -padding)
            textField.height(50)

            textField.delegate = self
        }

        firstNameTextField.topToSuperview(view.safeAreaLayoutGuide.topAnchor, offset: padding, usingSafeArea: true)

        lastNameTextField.topToBottom(of: firstNameTextField, offset: padding)

        numberTextField.topToBottom(of: lastNameTextField, offset: padding)

        raceTextField.topToBottom(of: numberTextField, offset: padding)

        searchButton.topToBottom(of: raceTextField, offset: padding)
        searchButton.leftToSuperview(view.leftAnchor, offset: padding)
        searchButton.rightToSuperview(view.rightAnchor, offset: -padding)
        searchButton.height(50)

        collectionView.topToBottom(of: searchButton, offset: padding)
        collectionView.edgesToSuperview(excluding: .top)
    }
    fileprivate func configureTextFields() {
        firstNameTextField.tag  = 0
        lastNameTextField.tag   = 1
        numberTextField.tag     = 2
        raceTextField.tag       = 3
    }
    fileprivate func configureButton() {
        view.addSubview(searchButton)

        searchButton.addTarget(self, action: #selector(searchRunners), for: .touchUpInside)
    }
    fileprivate func createLayout() -> UICollectionViewLayout {
        let itemSize    = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                 heightDimension: .fractionalHeight(1.0))
        let item        = NSCollectionLayoutItem(layoutSize: itemSize)


        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                               heightDimension: .estimated(100))
        let group   = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)
        let spacing = CGFloat(10)
        group.interItemSpacing = .fixed(spacing)


        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = spacing

        let padding = CGFloat(10)
        section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: padding, bottom: 0, trailing: padding)

        let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(80))
        let header     = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)

        section.boundarySupplementaryItems = [header]

        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }
    fileprivate func configureCollectionView() {
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: createLayout())

        collectionView.autoresizingMask = [.flexibleHeight]
        collectionView.backgroundColor  = .systemBackground

        collectionView.delegate     = self
        collectionView.dataSource   = self

        collectionView.register(RunnerCell.self, forCellWithReuseIdentifier: RunnerCell.reuseID)
        collectionView.register(Header.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: Header.reuseID)

        view.addSubview(collectionView)
    }
}

extension SearchRunnerVC : UICollectionViewDelegate, UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return runners.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RunnerCell.reuseID, for: indexPath) as? RunnerCell else { fatalError("Unable to dequeue runner cell")}

        cell.configure(runner: runners[indexPath.row])

        return cell
    }


    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: Header.reuseID, for: indexPath) as? Header else { fatalError("Unable to dequeue header")}
        header.title.text = "Résultats"
        header.seeButton.addTarget(self, action: #selector(seeAllTapped), for: .touchUpInside)
        header.separator.alpha = 0
        header.backgroundColor = collectionView.backgroundColor
        return header
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print(indexPath.item)
    }
}

Solution

  • Seems like your problem relates to the UITapGestureRecognizer you are adding to your view in configureSuperView(). The touches that would usually trigger the collectionView didSelectItemAt... delegate function are being sent to the gesture recognizer's handler, which is hideKeyboard().

    Comment the line with view.addGestureRecognizer(viewTap) and your code will work. If so, I can also help you with achieving the hideKeyboard functionality, just let me know.