1

I'm developing a card view like in Tinder. When cards X origin is bigger than a value which I declare, It moves out the screen. Otherwise, It sticks to center again. I'm doing all of these things inside UIPanGestureRecognizer function. I can move the view in Change state. However, It sometimes doesn't get into end state so card is neither moves out of the screen or stick to center again. It just stays in some weird place.

So My problem is that card should go out of the screen like in below screenshot or stick into center.

I tried solutions in below post but nothing worked:

UIPanGestureRecognizer not calling End state

UIPanGestureRecognizer does not switch to state "End" or "Cancel" if user panned x and y in negative direction

/// This method handles the swiping gesture on each card and shows the appropriate emoji based on the card's center.
@objc func handleCardPan(sender: UIPanGestureRecognizer) {

    // Ensure it's a horizontal drag
    let velocity = sender.velocity(in: self.view)
    if abs(velocity.y) > abs(velocity.x) {
        return
    }

    // if we're in the process of hiding a card, don't let the user interace with the cards yet
    if cardIsHiding { return }
    // change this to your discretion - it represents how far the user must pan up or down to change the option
    // distance user must pan right or left to trigger an option
    let requiredOffsetFromCenter: CGFloat = 80

    let panLocationInView = sender.location(in: view)
    let panLocationInCard = sender.location(in: cards[0])

    switch sender.state {
    case .began:
        dynamicAnimator.removeAllBehaviors()
        let offset = UIOffsetMake(cards[0].bounds.midX, panLocationInCard.y)
        // card is attached to center
        cardAttachmentBehavior = UIAttachmentBehavior(item: cards[0], offsetFromCenter: offset, attachedToAnchor: panLocationInView)
        //dynamicAnimator.addBehavior(cardAttachmentBehavior)
        let translation = sender.translation(in: self.view)
        print(sender.view!.center.x)
        sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: sender.view!.center.y)

        sender.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
    case .changed:
        //cardAttachmentBehavior.anchorPoint = panLocationInView
        let translation = sender.translation(in: self.view)
        print(sender.view!.center.x)
        sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: sender.view!.center.y)
        sender.setTranslation(CGPoint(x: 0, y: 0), in: self.view)

    case .ended:

        dynamicAnimator.removeAllBehaviors()

        if !(cards[0].center.x > (self.view.center.x + requiredOffsetFromCenter) || cards[0].center.x < (self.view.center.x - requiredOffsetFromCenter)) {
            // snap to center
            let snapBehavior = UISnapBehavior(item: cards[0], snapTo: CGPoint(x: self.view.frame.midX, y: self.view.frame.midY + 23))
            dynamicAnimator.addBehavior(snapBehavior)
        } else {
            let velocity = sender.velocity(in: self.view)
            let pushBehavior = UIPushBehavior(items: [cards[0]], mode: .instantaneous)
            pushBehavior.pushDirection = CGVector(dx: velocity.x/10, dy: velocity.y/10)
            pushBehavior.magnitude = 175
            dynamicAnimator.addBehavior(pushBehavior)

            // spin after throwing
            var angular = CGFloat.pi / 2 // angular velocity of spin
            let currentAngle: Double = atan2(Double(cards[0].transform.b), Double(cards[0].transform.a))

            if currentAngle > 0 {
                angular = angular * 1
            } else {
                angular = angular * -1
            }
            let itemBehavior = UIDynamicItemBehavior(items: [cards[0]])
            itemBehavior.friction = 0.2
            itemBehavior.allowsRotation = true
            itemBehavior.addAngularVelocity(CGFloat(angular), for: cards[0])
            dynamicAnimator.addBehavior(itemBehavior)

            showNextCard()
            hideFrontCard()

        }
    default:
        break
    }
}

image

Emre Önder
  • 2,408
  • 2
  • 23
  • 73
  • You haven't checked the `canceled` and `failed` states. For debugging, add those states and if you encounter either of these, you can still execute your `move` code based on the last touch location, or investigate why the gesture fails / gets cancelled. – Swapnil Luktuke Sep 21 '18 at 09:28

1 Answers1

0

I was checking If I'm swiping in horizontal with:

let velocity = sender.velocity(in: self.view)
if abs(velocity.y) > abs(velocity.x) {
    return
}

For some reason, It was getting in to return while I'm swiping horizontal. When I comment this block of code, everything started to work :)

Emre Önder
  • 2,408
  • 2
  • 23
  • 73