Logan Gallois Logan Gallois - 13 days ago 4
iOS Question

Interactive Dismiss ViewController

I have a storyboard like that :

enter image description here

Article View is presented from segue and animation :

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.

if segue.identifier == "showArticleFromArticles" {
let ViewToShow = segue.destinationViewController as! ArticleView
ViewToShow.articleToShow = ArticleToShow2
ViewToShow.transitioningDelegate = self
}

}


My animation :

class TransitionManager: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerInteractiveTransitioning, UIViewControllerTransitioningDelegate, UIViewControllerContextTransitioning {

weak var transitionContext: UIViewControllerContextTransitioning?

var sourceViewController: UIViewController! {
didSet {
print("set")
print(sourceViewController)
enterPanGesture = UIScreenEdgePanGestureRecognizer()
enterPanGesture.addTarget(self, action:"panned:")
enterPanGesture.edges = UIRectEdge.Left
let newSource = sourceViewController as! ArticleView
newSource.WebView.addGestureRecognizer(enterPanGesture)
}
}

let duration = 1.0
var presenting = true
var originFrame = CGRectNull

private var didStartedTransition = false
private var animated = false
private var interactive = false
private var AnimationStyle = UIModalPresentationStyle(rawValue: 1)
private var didFinishedTransition = false
private var percentTransition: CGFloat = 0.0
private var enterPanGesture: UIScreenEdgePanGestureRecognizer!

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView()
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!

// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransformMakeTranslation(container!.frame.width, 0)
let offScreenLeft = CGAffineTransformMakeTranslation(container!.frame.width, 0)

// start the toView to the right of the screen
toView.transform = offScreenRight

// add the both views to our view controller
container!.addSubview(toView)
container!.addSubview(fromView)

// get the duration of the animation
// DON'T just type '0.5s' -- the reason why won't make sense until the next post
// but for now it's important to just follow this approach
let duration = self.transitionDuration(transitionContext)

// perform the animation!
// for this example, just slid both fromView and toView to the left at the same time
// meaning fromView is pushed off the screen and toView slides into view
// we also use the block animation usingSpringWithDamping for a little bounce
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: UIViewAnimationOptions.TransitionFlipFromRight, animations: {

fromView.transform = offScreenLeft
toView.transform = CGAffineTransformIdentity

}, completion: { finished in

// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)

})
}

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return duration
}

func startInteractiveTransition(transitionContext: UIViewControllerContextTransitioning) {
interactive = true


// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView()
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!

// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransformMakeTranslation(container!.frame.width, 0)
let offScreenLeft = CGAffineTransformMakeTranslation(container!.frame.width, 0)

// start the toView to the right of the screen
toView.transform = offScreenRight

// add the both views to our view controller
container!.addSubview(toView)
container!.addSubview(fromView)

// get the duration of the animation
// DON'T just type '0.5s' -- the reason why won't make sense until the next post
// but for now it's important to just follow this approach
let duration = self.transitionDuration(transitionContext)

// perform the animation!
// for this example, just slid both fromView and toView to the left at the same time
// meaning fromView is pushed off the screen and toView slides into view
// we also use the block animation usingSpringWithDamping for a little bounce
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: UIViewAnimationOptions.TransitionFlipFromRight, animations: {

fromView.transform = offScreenLeft
toView.transform = CGAffineTransformIdentity

}, completion: { finished in

// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)

})


}

func containerView() -> UIView? {
return sourceViewController?.view
}

func viewControllerForKey(key: String) -> UIViewController? {
return sourceViewController?.storyboard!.instantiateViewControllerWithIdentifier(key)
}

func viewForKey(key: String) -> UIView? {
return sourceViewController?.storyboard!.instantiateViewControllerWithIdentifier(key).view
}

func initialFrameForViewController(vc: UIViewController) -> CGRect {
return vc.view.frame
}

func finalFrameForViewController(vc: UIViewController) -> CGRect {
return vc.view.frame
}

func isAnimated() -> Bool {
return animated
}

func isInteractive() -> Bool {
return interactive
}

func presentationStyle() -> UIModalPresentationStyle {
return AnimationStyle!
}

func completeTransition(didComplete: Bool) {
didFinishedTransition = didComplete
}

func updateInteractiveTransition(percentComplete: CGFloat) {
percentTransition = percentComplete
}

func finishInteractiveTransition() {
completeTransition(true)
}

func cancelInteractiveTransition() {
completeTransition(true)
}

func transitionWasCancelled() -> Bool {
return didFinishedTransition
}

func targetTransform() -> CGAffineTransform {
return CGAffineTransform()
}

func panned(pan: UIPanGestureRecognizer) {
//print(pan.translationInView(sourceViewController!.view))
switch pan.state {
case .Began:
animated = true
didStartedTransition = true
didFinishedTransition = false
sourceViewController?.dismissViewControllerAnimated(true, completion: nil)
if transitionContext != nil {
startInteractiveTransition(transitionContext!)
}
break
case .Changed:
percentTransition = CGFloat(pan.translationInView(sourceViewController!.view).x / sourceViewController!.view.frame.width)
print(percentTransition)
updateInteractiveTransition(percentTransition)
break
case .Ended, .Failed, .Cancelled:
animated = false
didStartedTransition = false
didFinishedTransition = true
finishInteractiveTransition()
break
case .Possible:
break
}
}


}

From Article View, I call dismiss view like that :

@IBAction func Quit(sender: UIBarButtonItem) {
self.dismissViewControllerAnimated(true, completion: nil)
}


and :

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.presenting = false
return transition
}


And i add the PanGesture like that :

let transition = TransitionManager()
self.transition.sourceViewController = self


But Pan Gesture just dismiss the view, and Interactive is not available
Because i call :

self.dismissViewControllerAnimated(true, completion: nil)


during UIPanGestureRecognizer.began

How can I do this ?

I am using Xcode 7, Swift 2, iOS 9

Thanks !

Answer

I found the solution :

i should just use

startInteractiveTransition

to instantiate some things

and use :

func updateInteractiveTransition(percentComplete: CGFloat) {
    if self.reverse {
        print(percentComplete)
        self.tovc.view.frame.origin.x = (self.fromvc.view.frame.maxX * (percentComplete)) - self.fromvc.view.frame.maxX
    }
}

to custom my transition.

Comments