iosswiftuicollectionviewcelluiswipegesturerecognizer

UISwipeGestureRecogniser in UICollectionViewCell issue


I have a UICollectionView where each cell has a left and right UISwipeGestureRecognizer which gives the illusion of flipping an image for a menu. The thing that I cannot figure out how to do is "closing/flipping" previously flipped cell before flipping another cell.

Here's screenshot of what it looks like now:

enter image description here

class Note: UICollectionViewCell {
var isFlipped = false

func addSwipeGestures() {
    let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeft(swipe:)))
    swipeLeft.direction = UISwipeGestureRecognizer.Direction.left
    contentView.addGestureRecognizer(swipeLeft)

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight(swipe:)))
    swipeRight.direction = UISwipeGestureRecognizer.Direction.right
    contentView.addGestureRecognizer(swipeRight)
}

@objc func swipeLeft(swipe: UISwipeGestureRecognizer) {
    if isFlipped {
        flipToBackView(options: .transitionFlipFromLeft)
    }
    else {
        flipToFrontView(options: .transitionFlipFromLeft)
    }
}

@objc func swipeRight(swipe: UISwipeGestureRecognizer) {
    if isFlipped {
        flipToBackView(options: .transitionFlipFromRight)
    }
    else {
        flipToFrontView(options: .transitionFlipFromRight)
    }
}

func flipToBackView(options: UIView.AnimationOptions ) {
    UIView.transition(with: backView, duration: 0.3, options: options, animations: { [unowned self] in
        self.coverImageView.isHidden = false
        self.titleLabel.isHidden = false
        self.titleView.isHidden = false
        self.isFlipped = !self.isFlipped
    })
}

func flipToFrontView(options: UIView.AnimationOptions) {
    UIView.transition(with: backView, duration: 0.3, options: options, animations: { [unowned self] in
        self.coverImageView.isHidden = true
        self.titleLabel.isHidden = true
        self.titleView.isHidden = true
        self.isFlipped = !self.isFlipped
    })
}
}

Solution

  • You could use the delegation pattern for this. E.g. you could add a protocol to the Note class:

    protocol FlipDelegate: class {
        func willFlip(note: Note)
    }
    

    Make the ViewController conform to this protocol, store the reference to the last flipped card and flip the last flipped card again:

        weak var lastFlippedNote: Note?
    
        func willFlip(_ note: Note) {
            lastFlippedNote?. flipToBackView(options: .transitionFlipFromLeft)
            lastFlippedNote = note
    
        }
    

    Add a weak reference to the Note class like weak var flipDelegate: FlipDelegate? and assign the viewController to the cell in the collectionView(_:cellForItemAt:). In your swipe actions you can call willFlip(_:) e.g. when you flip to the front side of your note like:

    @objc func swipeLeft(swipe: UISwipeGestureRecognizer) {
        if isFlipped {
            flipToBackView(options: .transitionFlipFromLeft)
        }
        else {
            flipToFrontView(options: .transitionFlipFromLeft)
            flipDelegate?.willFlip(note: self)
        }
    }
    
    @objc func swipeRight(swipe: UISwipeGestureRecognizer) {
        if isFlipped {
            flipToBackView(options: .transitionFlipFromRight)
        }
        else {
            flipToFrontView(options: .transitionFlipFromRight)
            flipDelegate?.willFlip(note: self)
        }
    }
    

    Regards