Search code examples
iosswiftuicollectionviewuicollectionviewcelldidselectrowatindexpath

Swift: Using didSelectItemAt indexPath func to only select the cell even if I tap on a UI element within it


Good afternoon. I am creating a simple little app and I have a simple "feature" in mind that I cannot figure out how to implement, being rather new to programming. I have a UICollectionView with cells within a cell of another UICollectionView and when I tap one of those cells they trigger the following didselect and diddeselect methods:

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

    if let cell = collectionView.cellForItem(at: indexPath) {

        cell.layer.borderColor = UIColor.flatBlack.cgColor
        cell.layer.borderWidth = 3
        cell.layer.cornerRadius = 7
        cell.backgroundColor = GradientColor(.topToBottom, frame: cell.frame, colors: [UIColor.flatRed.withAlphaComponent(0.2), UIColor.white])


    } else {return}

}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {

    if let cell = collectionView.cellForItem(at: indexPath) {
        cell.layer.borderColor = UIColor.clear.cgColor
        cell.layer.borderWidth = 0
        cell.layer.cornerRadius = 0
        cell.backgroundColor = .white
    } else {return}

}

Cell content: Its kinda long but i'll post the code if asked (programmatically created cells). But basically I have a few UIImageViews, two UITextViews, one UITextLabel and one UIButton inside each cell. (So the cells are declared in a separate class not in the class which is the UICollectionViewDelegate and DataSource).

Question: I want to add so that when I tap anywhere within the cells individual frame I want to have it selected even if I tap on a UITextView (at moment if I tap the textview it goes into edit mode of that view). I want to be able to edit the textview if I tap a second time on it. - How can I implement this?

Cell creation Code:

class EventsCell: UICollectionViewCell {
  override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = UIColor.white
    setupViews()


}
//MARK: - Declaration of cell organelles.
//separatorView for a separating line between cells

let textView: GrowingTextView = {   //GrowingTextView is a pod it is a regular UITextView but with some perks.
    let tv = GrowingTextView()
    tv.backgroundColor = .clear
    tv.allowsEditingTextAttributes = true
    tv.isScrollEnabled = false
    tv.font = UIFont(name: "Didot", size: 16)
    tv.textContainerInset = UIEdgeInsetsMake(4, 4, 4, 6)
    tv.placeholder = "Write your event text here"
    tv.placeholderColor = UIColor.lightGray
    tv.autoresizingMask = .flexibleHeight
    tv.isUserInteractionEnabled = false
    return tv
}()



let eventPlaceholderMarkImage: UIImageView = {
    let iv = UIImageView()
    iv.image = UIImage(named: "placeHolderEventTitleMark")
    return iv
}()

func setupViews() {


    addSubview(textView)
    addSubview(eventPlaceholderMarkImage)


    let eventsPinImageH = frame.width / 2 - 7
    let cellHeight = frame.height
    let cellWidth = frame.width

    //MARK: - Constraints for EventsCell

    addConstraintsWithFormat(format: "H:|-16-[v0(\(frame.width - 32))]-16-|", views: textView)
    addConstraintsWithFormat(format: "V:|-47-[v0]-16-|", views: textView)




    addConstraint(NSLayoutConstraint(item: eventPlaceholderMarkImage, attribute: .bottom, relatedBy: .equal, toItem: textView, attribute: .top, multiplier: 1, constant: -5))
    addConstraint(NSLayoutConstraint(item: eventPlaceholderMarkImage, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20)) 
    //Followed by much more constraints
    required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

Then in the class I create the UICollectionView:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EventCellID, for: indexPath)

    return cell
}

Thank you for reading my post!


Solution

  • func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    
        if let cell = collectionView.cellForItem(at: indexPath) {
    
            cell.yourTextView.isUserInteractionEnbled = true //1
    
    
            cell.layer.borderColor = UIColor.flatBlack.cgColor
            cell.layer.borderWidth = 3
            cell.layer.cornerRadius = 7
            cell.backgroundColor = GradientColor(.topToBottom, frame: cell.frame, colors: [UIColor.flatRed.withAlphaComponent(0.2), UIColor.white])
    
    
        } else {return}
    
    }
    
    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    
        if let cell = collectionView.cellForItem(at: indexPath) {
            cell.layer.borderColor = UIColor.clear.cgColor
            cell.layer.borderWidth = 0
            cell.layer.cornerRadius = 0
            cell.backgroundColor = .white
        } else {return}
    
    }
    
    override func viewWillAppear(_ animated: Bool) {        
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: Notification.Name.UIKeyboardWillHide, object: nil)
    }
    
    
    @objc func keyboardWillDisappear() {
    
        cell.yourTextView.isUserInteractionEnbled = false //2
    }
    

    When creating the cell :

    ...
    cell.yourTextView.isUserInteractionEnabled = false // 3
    

    1 : the first Time your cell is being selected, your textView won't be selectable due to what we did at step (3), after the first tap we're enabling the textView for the second touch

    2 : Whenever we dismiss the keyboard after editing the textview we are setting interactions to false so that we would be able to select the cell on tap and not the textView