Nizam
Nizam

Reputation: 4699

Swift - Tinder effect

How can I achieve Tinder effect in Swift?

I mean, I have an image and want to accept if I swipe to right and reject if I swipe to left.

I can do it with the code bellow:

@IBAction func SwipeRight(sender: UISwipeGestureRecognizer) {
    UIView.animateWithDuration(1) {
        self.Imagem.center = CGPointMake(self.Imagem.center.x - 150, self.Imagem.center.y )
    }
    //other things after acception
}

and

@IBAction func SwipeLeft(sender: UISwipeGestureRecognizer) {
    UIView.animateWithDuration(1) {
        self.Imagem.center = CGPointMake(self.Imagem.center.x + 150, self.Imagem.center.y )
    }
    //other things after rejection
}

But this way the user can't cancel the action. I want that if the user swipes to a delta distance from the edge (left or right), it would appear an image to let the user now that, if he ends the movement, the action will take place. Otherwise, the user can, without ending the movement, go back to a distance bigger than delta, and the action would be cancelled.

Upvotes: 6

Views: 5784

Answers (3)

swathy krishnan
swathy krishnan

Reputation: 916

Try this:

https://github.com/cwRichardKim/TinderSimpleSwipeCards

You can find a better solution here with rotation. See DraggableView.m

-(void)beingDragged:(UIPanGestureRecognizer *)gestureRecognizer
{
    //%%% this extracts the coordinate data from your swipe movement. (i.e. How much did you move?)
    xFromCenter = [gestureRecognizer translationInView:self].x; //%%% positive for right swipe, negative for left
    yFromCenter = [gestureRecognizer translationInView:self].y; //%%% positive for up, negative for down

    //%%% checks what state the gesture is in. (are you just starting, letting go, or in the middle of a swipe?)
    switch (gestureRecognizer.state) {
            //%%% just started swiping
        case UIGestureRecognizerStateBegan:{
            self.originalPoint = self.center;
            break;
        };
            //%%% in the middle of a swipe
        case UIGestureRecognizerStateChanged:{
            //%%% dictates rotation (see ROTATION_MAX and ROTATION_STRENGTH for details)
            CGFloat rotationStrength = MIN(xFromCenter / ROTATION_STRENGTH, ROTATION_MAX);

            //%%% degree change in radians
            CGFloat rotationAngel = (CGFloat) (ROTATION_ANGLE * rotationStrength);

            //%%% amount the height changes when you move the card up to a certain point
            CGFloat scale = MAX(1 - fabsf(rotationStrength) / SCALE_STRENGTH, SCALE_MAX);

            //%%% move the object's center by center + gesture coordinate
            self.center = CGPointMake(self.originalPoint.x + xFromCenter, self.originalPoint.y + yFromCenter);

            //%%% rotate by certain amount
            CGAffineTransform transform = CGAffineTransformMakeRotation(rotationAngel);

            //%%% scale by certain amount
            CGAffineTransform scaleTransform = CGAffineTransformScale(transform, scale, scale);

            //%%% apply transformations
            self.transform = scaleTransform;
            [self updateOverlay:xFromCenter];

            break;
        };
            //%%% let go of the card
        case UIGestureRecognizerStateEnded: {
            [self afterSwipeAction];
            break;
        };
        case UIGestureRecognizerStatePossible:break;
        case UIGestureRecognizerStateCancelled:break;
        case UIGestureRecognizerStateFailed:break;
    }
}

Upvotes: 0

user3579086
user3579086

Reputation: 123

It's better to use UIPanGestureRecognizer here and manage its states, as you've already figured out. For managing cards it would be good solution to create class-manager that will handle interactions between cards(moving background cards on swiping the front). You can look at the implementation of card and manager here, there are implementation of dragging, moving background cards and revert animations. https://github.com/Yalantis/Koloda

Upvotes: 1

Nizam
Nizam

Reputation: 4699

I would like to thanks the people who suggested solutions. Follow the solution I developed with a huge help of a lot of people from Stack Overflow:

@IBAction func Arrastei(sender: UIPanGestureRecognizer) {
    var origem =  CGPoint(x: 0, y: 0)
    var translation : CGPoint = sender.translationInView(Imagem)

    var txy : CGAffineTransform = CGAffineTransformMakeTranslation(translation.x, -abs(translation.x) / 15)
    var rot : CGAffineTransform = CGAffineTransformMakeRotation(-translation.x / 1500)
    var t : CGAffineTransform = CGAffineTransformConcat(rot, txy);
    Imagem.transform = t

    if (translation.x > 100) {
        LbResultado.textColor = btVerdadeiro.textColor
        LbResultado.text = btVerdadeiro.text
        LbResultado.hidden = false
    } else {
        if (translation.x < -100) {
            LbResultado.textColor = btFalso.textColor
            LbResultado.text = btFalso.text
            LbResultado.hidden = false
        } else {
            LbResultado.hidden = true
        }
    }


    if sender.state == UIGestureRecognizerState.Ended {
        if (translation.x > 100) {
            objJogo.Rodada_Vigente!.Responder(true)
        } else {

            if (translation.x < -100) {
                objJogo.Rodada_Vigente!.Responder(false)
            } else {
                sender.view.transform = CGAffineTransformMakeTranslation(origem.x, origem.y)
                sender.view.transform = CGAffineTransformMakeRotation(0)
            }
        }
    }
}

This solution uses:

Imagem --> UIImageView - to be accepted or rejected

LbResultado --> UITextView - to show the user he is in acceptance or rejection area

There is no math calculations to set rotation and translation. I used values that give me a visually good effect.

The action (acceptance and rejection) area is when the user drag image more than 100 pixels to left (reject) or right (accept). If the user ends the movement out the action area, the image will go back to its original position.

I will be glad if someone suggests improvements to this code.

Upvotes: 12

Related Questions