0
votes

everyone i've been tearing out my hair trying to find a solution to an interactive view controller transition where you use the pan gesture in the downward direction to bring a full screen view controller from the top to the bottom. Has anyone run across or created any code like this. Below is my code. I already have the dismiss gesture down but cant figure out how to present the view controller by swiping down on the screen. PLEASE HELP!!!

 import UIKit    
 class ViewController: UIViewController {

let interactor = Interactor()
   var interactors:Interactor? = nil
    let Mview = ModalViewController()
let mViewT: ModalViewController?  = nil
var presentedViewControllers: UIViewController?

override func viewDidLoad() {
    Mview.transitioningDelegate = self
    Mview.modalPresentationStyle = .FullScreen
}

   @IBAction func cameraSlide(sender: UIPanGestureRecognizer) {



    let percentThreshold:CGFloat = 0.3

    // convert y-position to downward pull progress (percentage)
    let translation = sender.translationInView(Mview.view)
    let verticalMovement = translation.y / UIScreen.mainScreen().bounds.height
    let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
    let downwardMovementPercent = fminf(downwardMovement, 1.0)
    let progress = CGFloat(downwardMovementPercent)

    guard let interactor = interactors else { return }

    switch sender.state {
    case .Began:

        interactor.hasStarted = true
        self.presentViewController(Mview, animated: true, completion: nil)
    case .Changed:
        interactor.shouldFinish = progress > percentThreshold
        interactor.updateInteractiveTransition(progress)
    case .Cancelled:
        interactor.hasStarted = false
        interactor.cancelInteractiveTransition()
    case .Ended:
        interactor.hasStarted = false
        if !interactor.shouldFinish {
            interactor.cancelInteractiveTransition()
        } else {
            interactor.finishInteractiveTransition()
        }        default:
        break
    }
}

}

extension ViewController: UIViewControllerTransitioningDelegate { func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return DismissAnimator() }

func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return interactor.hasStarted ? interactor : nil
}

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return PresentAnimator()
}
func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return interactor.hasStarted ? interactor : nil
}

}

  class PresentAnimator: NSObject {

}

extension PresentAnimator: UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return 1.0 }

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    guard

        let fromVC2 = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
    let toVC2 = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey),
        let containerView2 = transitionContext.containerView() else {return}

    let initialFrame = transitionContext.initialFrameForViewController(fromVC2)
    toVC2.view.frame = initialFrame
    toVC2.view.frame.origin.y = -initialFrame.height * 2


    containerView2.addSubview(fromVC2.view)
    containerView2.addSubview(toVC2.view)

    let screenbounds = UIScreen.mainScreen().bounds
    let Stage = CGPoint(x: 0, y: 0)
    let finalFrame = CGRect(origin: Stage, size: screenbounds.size)

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        toVC2.view.frame = finalFrame
        }, completion: { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    }
    )



}

}

   class ModalViewController: UIViewController {

let interactors = Interactor()
var interactor:Interactor? = nil

@IBAction func close(sender: UIButton) {
    dismissViewControllerAnimated(true, completion: nil)
}




@IBAction func handleGesture(sender: UIPanGestureRecognizer) {

    let percentThreshold:CGFloat = 0.3

    // convert y-position to downward pull progress (percentage)
    let translation = sender.translationInView(self.view)
    let verticalMovement = translation.y / -view.bounds.height * 2
    let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
    let downwardMovementPercent = fminf(downwardMovement, 1.0)
    let progress = CGFloat(downwardMovementPercent)

    guard let interactor = interactor else { return }

    switch sender.state {
    case .Began:
        interactor.hasStarted = true
        dismissViewControllerAnimated(true, completion: nil)
    case .Changed:
        interactor.shouldFinish = progress > percentThreshold
        interactor.updateInteractiveTransition(progress)
    case .Cancelled:
        interactor.hasStarted = false
        interactor.cancelInteractiveTransition()
    case .Ended:
        interactor.hasStarted = false
        if !interactor.shouldFinish {
            interactor.cancelInteractiveTransition()
        } else {
            interactor.finishInteractiveTransition()
        }        default:
        break
    }
}

}

    import UIKit

class DismissAnimator: NSObject { }

extension DismissAnimator : UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return 1.0 }

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    guard
        let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
        let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey),
        let containerView = transitionContext.containerView()
        else {
            return
    }

    containerView.insertSubview(toVC.view, belowSubview: fromVC.view)

    let screenBounds = UIScreen.mainScreen().bounds
    let topLeftCorner = CGPoint(x: 0, y: -screenBounds.height * 2)
    let finalFrame = CGRect(origin: topLeftCorner, size: screenBounds.size)

    UIView.animateWithDuration(
        transitionDuration(transitionContext),animations: {fromVC.view.frame = finalFrame},
        completion: { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        }
    )

       }

}

1
Did you ever get this to work ive been trying to figure this out myselfuser6520705

1 Answers

1
votes

If you want a simple Pan Gesture to switch between UIViewControllers, you can check out this:

http://www.appcoda.com/custom-segue-animations/

If you want it to be interactive, as in you can go back and forth between VCs without having to complete the whole transition, I suggest you check out this:

https://www.youtube.com/watch?v=3jAlg5BnYUU

If you want to go even further and have a custom dismissing animation, then look no further than this:

https://www.raywenderlich.com/110536/custom-uiviewcontroller-transitions