WorldDownTown / ZoomTransitioning

ZoomTransitioning provides a custom transition with image zooming animation and swiping the screen edge.
MIT License
671 stars 54 forks source link

Navigation Controller Interactive pop gesture in IOS10 #6

Closed manuelCarlos closed 8 years ago

manuelCarlos commented 8 years ago

Hi! This is great work. Congrats! I'm working on a project for IOS10. I'm not using ZoomTransitioning, but I do use your approach to retrieve the navigation controller's default interactivePopGesture recogniser and tie it to the behavior of my own gesture, which drives my custom transition. It worked great on IOS9 but not at all in IOS10. At first i thought there was something wrong with my code, but I tried your zoomTransitioning Demo and it showed the same result as mine: on IOS10 the edge pan gesture drives the default pop animation and not the custom animation transition :( I tried to fix this with some fine tuning of the ZoomInteractiveTransition gesture delegate but nothing worked. I can't see anything wrong with the code. Was wondering if you might know of a fix. Thanks!

WorldDownTown commented 8 years ago

Hi, thank you for opening the issue. I realized the same problem. In iOS 10, it seems that UINavigationControllerDelegate does not call navigationController:interactionControllerFor: and navigationController:animationControllerFor:from:to:. But I solved this problem. Check this commit (https://github.com/WorldDownTown/ZoomTransitioning/commit/b043764ffad9d084c6122f57742b921cb0739c25). Furthermore I made branches for new Swift version. You can build this immediately in Xcode 8 GM seed. https://github.com/WorldDownTown/ZoomTransitioning/tree/swift-2.3 https://github.com/WorldDownTown/ZoomTransitioning/tree/swift-3

zoom_transitioning

manuelCarlos commented 8 years ago

Wow, that's great! Thank you for the quick reply. I'll check it out. Have a great weekend!

manuelCarlos commented 8 years ago

It's looking better, but once you start the edge pan gesture there's no way of canceling the transition. Apparently the UIPercentDrivenInteractiveTransition's cancel() method does not interrupt the pop transition once it's initiated. ( UIKit shenanigans i suspect ) To work around this, you might consider replacing the cancel() call with update(0.0), to revert the animation back. It will look like this:

 case .cancelled, .ended:
        guard let view = recognizer.view else { return }
        let progress = recognizer.translation(in: view).x / view.bounds.width
        let velocity = recognizer.velocity(in: view).x

        if progress > 0.33 || velocity > 1000.0 {
            finish()
        } else {
             update(0.0)
        }
        interactive = false
    default:
        break
    }

Thanks again. Was really helpful 👍

manuelCarlos commented 8 years ago

Just noticed that the approach I suggested above works fine for the edge pan gesture transition, but will freeze the back button on navigation controller, sorry. 🙁

manuelCarlos commented 8 years ago

I think this time i found a IOS10 workaround that works, :

// MARK: - UIGestureRecognizerDelegate
extension ZoomInteractiveTransition: UIGestureRecognizerDelegate {

public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    interactive = true
    if #available(iOS 10.0, *) {
     // store the popped viewController, to be added back to the navigation stack
      vc = navigationController?.popViewController(animated: true)
    }
    return true
}

On ZoomInteractiveTransition class

weak var vc: UIViewController?
  . . .

    // on handlePanGestureRecognizer(_:)
  case .cancelled, .ended:
        . . .
        if progress > 0.33 || velocity > 1000.0 {
            finish()
        } else {
            // add back the popped view controller into the navigation stack
            navigationController?.viewControllers.append(vc!)
            update(0.0)
            cancel()

        }
        interactive = false
    default:
        break
    }

On ZoomTransitioning's animateTransitionForPop(_:), call transitionContext.completeTransition always with true

fileprivate func animateTransitionForPop(_ transitionContext: UIViewControllerContextTransitioning) {
   ...
    UIView.animate(
       ..
        },
        completion: { _ in
           ...

           transitionContext.completeTransition(true)
    })
}

This is the best i could come up with. It's pretty awful. Give it a try, hope it helps.

WorldDownTown commented 8 years ago

Oh, great idea! I checked that code, then it worked fine for me. I have adopted your solution.

WorldDownTown commented 8 years ago

So the problem was solved, I close this issue.