Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Swift 2.0 #20

Open
toygar-zzz opened this issue Sep 30, 2015 · 3 comments
Open

Support Swift 2.0 #20

toygar-zzz opened this issue Sep 30, 2015 · 3 comments

Comments

@toygar-zzz
Copy link

No description provided.

@toygar-zzz toygar-zzz changed the title Supporting Swift 2.0 Support Swift 2.0 Sep 30, 2015
@assisjeferson
Copy link

I translate the class CardView by @clsource

I tested using iPhone 6s running iOS 9.2

import UIKit
import Darwin
import Swift


// MARK: CardViewDelegate
@objc protocol CardViewDelegate {
    /*!
    * Method called when the view will begin pan gesture
    * @param Card * Card
    */
    optional func willBeginSwipeInCard(card: CardView)

    /*!
    * Method called when the view did end pan gesture
    * @param Card * Card
    */
    optional func didEndSwipeInCard(card: CardView)

    /*!
    * Method called when the view did not reach a detected position
    * @param Card * Card
    */
    optional func didCancelSwipeInCard(card: CardView)

    /*!
    * Method called when the view was swiped left
    * @param Card * Card
    */
    optional func swipedLeftInCard(card: CardView)

    /*!
    * Method called when the view was swiped right
    * @param Card * Card
    */
    optional func swipedRightInCard(card: CardView)

    /*!
    * Method called when the view was swiped up
    * @param Card * Card
    */
    optional func swipedUpInCard(card: CardView)

    /*!
    * Method called when the view was swiped down
    * @param Card * Card
    */
    optional func swipedDownInCard(card: CardView)

    /*!
    * Method called when the view button was pressed
    * @param Card * Card;
    */
    optional func wasTouchedDownInCard(card: CardView)

    /*!
    *    Method called when the state was changed
    *
    *    @param  Card * Card;
    */
    optional func didChangeStateInCard(card: CardView)

    /*!
    *    Ask the delegate if the card should move
    *
    *    @param Card the card
    *
    *    @return YES if the card should move
    */
    func shouldMoveCard(card: CardView) -> Bool
}

// MARK: CardView Enums
enum CardState : Int {
    case Idle = 0, Moving, Gone
}

enum CardPosition : Int {
    case Top = 0, Back
}

// Constants Declaration

// This constant represent the distance from the center
// where the action applies. A higher value means that
// the user needs to draw the view further in order for
// the action to be executed.
let X_ACTION_MARGIN : CGFloat = 120

// This constant is the distance from the center. But vertically
let Y_ACTION_MARGIN : CGFloat = 100

// This constant represent how quickly the view shrinks.
// The view will shrink when is beign moved out the visible
// area.
// A Higher value means slower shrinking
let SCALE_QUICKNESS = 4

// This constant represent how much the view shrinks.
// A Higher value means less shrinking
let SCALE_MAX : Float = 0.93

// This constant represent the rotation angle
let ROTATION_ANGLE = M_PI / 8

// This constant represent the maximum rotation angle
// allowed in radiands.
// A higher value enables more rotation for the view
let ROTATION_MAX : CGFloat = 1

//// This constant defines how fast
// the rotation should be.
// A higher values means a faster rotation.
let ROTATION_QUICKNESS : CGFloat = 320

// MARK: CardView
class CardView: UIView {


    // MARK: Internal Variables
    var state : CardState = .Idle
    var position : CardPosition = .Top

    var xFromCenter : CGFloat = 0
    var yFromCenter : CGFloat = 0
    var originalPoint : CGPoint = CGPoint(x: 0, y: 0)

    var delegate : CardViewDelegate

    // MARK: Init
    init(frame: CGRect, delegate: CardViewDelegate) {
        self.delegate = delegate

        super.init(frame: frame)
        self.setup()
    }

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

    // MARK: Setup Method
    private func setup() {
        // Draw Shadow
        // And round the view
        self.layer.cornerRadius = 10;
        self.layer.shadowRadius = 3;
        self.layer.shadowOpacity = 0.2;
        self.layer.shadowOffset = CGSizeMake(1,1);
        self.backgroundColor = UIColor.whiteColor()

        //Register Pan Gesture and Delegates
        let panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePanGesture:")
        self.addGestureRecognizer(panRecognizer)
    }

    // MARK: Pan Gesture Recognizer Handlers
    @objc private func handlePanGesture(panRecognizer: UIPanGestureRecognizer) {

        self.xFromCenter = panRecognizer.translationInView(self).x;
        self.yFromCenter = panRecognizer.translationInView(self).y;


        let isPossibleMove = self.delegate.shouldMoveCard(self)

        switch(panRecognizer.state) {
        case .Began:
            self.originalPoint = self.center

            if isPossibleMove {
                self.delegate.willBeginSwipeInCard?(self)
            }
            break;
        case .Changed:

            if isPossibleMove {
                self.animateView()
            }
            break;
        case .Ended:
            if isPossibleMove {
                self.detectSwipeDirection()
            }
            break;
        default:

            break;
        }
    }

    // MARK: Helper Methods

    /*!
    * Rotates the view
    * and changes its scale and position
    */
    private func animateView() {
        // Do some black magic math
        // for rotating and scale

        // Gets the rotation quickness
        // see constants.
        let rotationQuickness = min(self.xFromCenter / ROTATION_QUICKNESS, ROTATION_MAX)

        // Change the rotation in radians
        let rotationAngle = CGFloat(ROTATION_ANGLE) * rotationQuickness

        // the height will change when the view reaches certain point
        let scale = CGFloat(max(1 - fabsf(Float(rotationQuickness)) / Float(SCALE_QUICKNESS), SCALE_MAX))

        // move the object center depending on the coordinate
        self.center = CGPoint(x: self.originalPoint.x + self.xFromCenter, y: self.originalPoint.y + self.yFromCenter)

        // rotate by the angle
        let rotateTransform = CGAffineTransformMakeRotation(rotationAngle)

        // scale depending on the rotation
        let scaleTransform = CGAffineTransformScale(rotateTransform, scale, scale)

        // apply transformations
        self.transform = scaleTransform
    }


    /*!
    * With all the values fetched
    * from the pan gesture
    * gets the direction of the swipe
    * when the swipe is done
    */
    private func detectSwipeDirection(){
        if self.xFromCenter > X_ACTION_MARGIN {
            self.performRightAnimation()
        }
        else if self.xFromCenter < -X_ACTION_MARGIN {
            self.performLeftAnimation()
        }
        else if self.yFromCenter < -Y_ACTION_MARGIN {
            self.performUpAnimation()
        }
        else if self.yFromCenter > Y_ACTION_MARGIN {
            self.performCenterAnimation()
        }
        else {
            self.performCenterAnimation()
        }

        // And tell the delegate
        // that the swipe just finished

        self.delegate.didEndSwipeInCard?(self)
    }

    private func changeStateToIdle() {
        // Idle state indicates that the card
        // is showing in the view, but not moving.

        self.state = .Idle
    }

    private func changeStateToGone() {
        // Gone state indicates that the card
        // was removed from the view

        self.state = .Gone
    }

    private func changeStateToMoving() {
        self.state = .Moving

        // Cancel Swipe if Moving but not should
        if self.delegate.shouldMoveCard(self) {
            self.performCenterAnimation()
        }
    }

    // MARK: Animation Methods

    /*!
    * The view will go to the right
    */
    private func performRightAnimation() {
        let finishPoint = CGPoint(x: 500, y: 2 * self.yFromCenter + self.originalPoint.y)

        UIView.animateWithDuration(0.3,
            delay: 0,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                self.center = finishPoint
            }) { (finished) -> Void in
                self.removeFromSuperview()
                self.changeStateToGone()
                self.delegate.swipedRightInCard?(self)
        }
    }

    /*!
    * The view will got to the left
    */
    private func performLeftAnimation() {
        let finishPoint = CGPoint(x: -500, y: 2 * self.yFromCenter + self.originalPoint.y)

        UIView.animateWithDuration(0.3,
            delay: 0,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                self.center = finishPoint
            }) { (finished) -> Void in
                self.removeFromSuperview()
                self.changeStateToGone()
                self.delegate.swipedLeftInCard?(self)
        }
    }

    /*!
    * The view will go up
    * do not remove from view
    * just perfom some goofy moves
    */
    private func performUpAnimation() {
        UIView.animateWithDuration(0.7,
            delay: 0,
            usingSpringWithDamping: 0.56,
            initialSpringVelocity: 0.0,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                self.center = self.originalPoint
                self.transform = CGAffineTransformMakeRotation(0)
            }) { (finished) -> Void in
                self.changeStateToIdle()
                self.delegate.swipedUpInCard?(self)
        }
    }

    /*!
    * The view will go down
    * do not remove from view
    * just perfom some goofy moves
    */
    private func performDownAnimation() {
        UIView.animateWithDuration(0.7,
            delay: 0,
            usingSpringWithDamping: 0.56,
            initialSpringVelocity: 0.0,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                self.center = self.originalPoint
                self.transform = CGAffineTransformMakeRotation(0)
            }) { (finished) -> Void in
                self.changeStateToIdle()
                self.delegate.swipedDownInCard?(self)
        }
    }

    /*!
    * The view will go to the center
    * (cancel swipe) and reset the values
    */
    private func performCenterAnimation() {
        UIView.animateWithDuration(0.7,
            delay: 0,
            usingSpringWithDamping: 0.56,
            initialSpringVelocity: 0.0,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                self.center = self.originalPoint
                self.transform = CGAffineTransformMakeRotation(0)
            }) { (finished) -> Void in
                self.changeStateToIdle()
                self.delegate.didCancelSwipeInCard?(self)
        }
    }

    // MARK: Programatically Swipe Methods
    func swipeLeft() {

        self.changeStateToMoving()

        self.performLeftAnimation()
    }

    func swipeRight() {
        self.changeStateToMoving()

        self.performRightAnimation()
    }

    func swipeUp() {
        //TODO: Implement this
    }

    func swipeDown() {
        //TODO: Implement this
    }

    func cancelSwipe() {
        self.performCenterAnimation()
    }
}

@toygar-zzz
Copy link
Author

Thanks @assisjeferson

@jpsanabria
Copy link

Awesome @assisjeferson

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants