Kristofer
Kristofer

Reputation: 817

Why is my collection view cell so hard to tap?

I have a CollectionViewController and multiple cells. However when I seem to tap onto one of those cells I would need multiple taps before the didSelectItemAt would read. My cells are spaced out evenly, at least big enough for them to be tapped on. I only get this problem on a real device and not on the simulator.

Here is my code

class TimeAvailabilityCell:UICollectionViewCell{

private let container:UIView = {
    let view = UIView()
    view.isUserInteractionEnabled = false
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .white
    view.layer.borderWidth = 1
    view.layer.borderColor = UIColor.systemBlue.cgColor
    view.layer.cornerRadius = 8
    return view
}()

public let timeLabel:UILabel = {
    let label = UILabel()
    label.isUserInteractionEnabled = false
    label.translatesAutoresizingMaskIntoConstraints = false
    label.numberOfLines = 0
    label.font = UIFont(name: "AppleSDGothicNeo-Regular", size: 18)
    label.textColor = .systemBlue
    return label
}()

override init(frame: CGRect) {
    super.init(frame:frame)

    self.backgroundColor = .green

    self.addSubview(container)
    container.widthAnchor.constraint(equalToConstant: 100).isActive = true
    container.heightAnchor.constraint(equalToConstant: 50).isActive = true
    container.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
    container.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    container.addSubview(timeLabel)
    timeLabel.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
    timeLabel.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}

And this is my CollectionViewController

class TimeSelectServiceController: UICollectionViewController, UICollectionViewDelegateFlowLayout{

var timeAvailableArray = [String]()
var timeTitle = ""

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)

    setupCollectionView()
}

override func viewDidLayoutSubviews() {
    self.updateCollectionView()
}

func setupCollectionView(){

    let inset = UIEdgeInsets(top: 0, left: 25, bottom: 80, right: 25)
    collectionView.contentInset = inset

    self.edgesForExtendedLayout = UIRectEdge.bottom
    collectionView.backgroundColor = .white
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.register(TimeAvailabilityCell.self, forCellWithReuseIdentifier: "cell")
    collectionView.register(SectionTitleHeader.self, forSupplementaryViewOfKind:UICollectionView.elementKindSectionHeader, withReuseIdentifier: "SectionTitleHeader")

    collectionView.allowsSelection = true
}

override func numberOfSections(in collectionView: UICollectionView) -> Int {
    1
}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    timeAvailableArray.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TimeAvailabilityCell
    let model = timeAvailableArray[indexPath.row]
    cell.timeLabel.text = model.description
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: self.collectionView.frame.width, height: 50)
}

override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

    let reusableview = UICollectionReusableView()
    switch kind {
    case UICollectionView.elementKindSectionHeader:
        //FOR HEADER VIEWS
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionTitleHeader", for: indexPath) as! SectionTitleHeader

        headerView.title.text = timeTitle
        headerView.seeAll.isHidden = true
        headerView.backgroundColor = .white
        return headerView
    default:
        return reusableview
    }

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if(section == 0){
        return CGSize(width: view.frame.width, height: 100)
    }
    return CGSize(width: view.frame.width, height: 100)
}

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let model = timeAvailableArray[indexPath.row]

    BookServiceDetails.details.serviceDate = timeTitle + " at " + model.description

    let viewController = ConfirmAppointmentController()
    self.navigationController?.pushViewController(viewController, animated: true)

    collectionView.deselectItem(at: indexPath, animated: true)
}




func updateCollectionView () {
    DispatchQueue.main.async(execute: {
        self.collectionView.reloadData()
    })
}

}

EDIT

It seems like the more cells I have the harder it is to click on one.

Upvotes: 0

Views: 530

Answers (2)

Kristofer
Kristofer

Reputation: 817

I have no idea how this has anything to do with it but I removed collectionView.dataSource = self and everything works fine now.

Upvotes: 0

Eelco Koelewijn
Eelco Koelewijn

Reputation: 113

In TimeAvailabilityCell add the sub-views to the contentView instead of the self. Disabling user-interaction on the sub-views should not matter.

From the documentation: "To configure the appearance of your cell, add the views needed to present the data item’s content as subviews to the view in the contentView property. Do not directly add subviews to the cell itself."

override init(frame: CGRect) {
    super.init(frame:frame)

    self.backgroundColor = .green

    contentView.addSubview(container)
    container.widthAnchor.constraint(equalToConstant: 100).isActive = true
    container.heightAnchor.constraint(equalToConstant: 50).isActive = true
    container.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
    container.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    container.addSubview(timeLabel)
    timeLabel.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
    timeLabel.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
}

This:

    override func viewDidLayoutSubviews() {
        self.updateCollectionView()
    }

    func updateCollectionView () {
        DispatchQueue.main.async(execute: {
            self.collectionView.reloadData()
        })
    }

Creates an endless loop, calling reloadData on the collection-view, triggers viewDidLayoutSubviews. Basically the collection-view is reloading the cells constantly, which causes selecting cell to work poorly.

The following blogs are a good reference on how-to setup and work with collection-views; either with storyboards or programmatically. It should give some more insights in how-to setup and configure your collection-view.

Upvotes: 1

Related Questions