1

I have a tableViewController in a containerView of another viewController.

When an image is tapped, a custom transition occurs to another viewController to view the image. The transition works well.

When the custom transition takes place though viewWillDisappear is called on the containerView's tableViewController and then viewWillAppear again when the presented viewController is dismissed (again with a transition).

This is causing some unusual scrolling occasionally in the tableView.

What I would like is to present the imageViewer with a transition but overCurrentContext.

I have tried what people suggest which is the following:

self.definesPresentationContext = true
vc.modalPresentationStyle = .overCurrentContext
vc.transitioningDelegate = self
self.present(vc, animated: true, completion: nil)

Unfortunately this is not working and when the imageViewController is dismissed, initially the transition back is correct and the tableViewController can be seen. But once the transition is complete the view goes black.

I think this may have to do with the fact that I'm using a containerView. But not sure and not sure how to resolve this.

This is the animator method I'm using:

private var image: UIImage?
private var fromDelegate: ImageTransitionProtocol?
private var toDelegate: ImageTransitionProtocol?

// MARK: Setup Methods

func setupImageTransition(image: UIImage, fromDelegate: ImageTransitionProtocol, toDelegate: ImageTransitionProtocol) {
    self.image = image
    self.fromDelegate = fromDelegate
    self.toDelegate = toDelegate

}

// MARK: UIViewControllerAnimatedTransitioning

// 1: Set animation speed
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.4
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView
        // 2: Get view controllers involved
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!

        // 3: Set the destination view controllers frame
        toVC.view.frame = fromVC.view.frame

        // 4: Create transition image view
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFill
        imageView.frame = (fromDelegate == nil) ? CGRect() : fromDelegate!.imageWindowFrame()
        imageView.clipsToBounds = true
        containerView.addSubview(imageView)

        // 5: Create from screen snapshot

        fromDelegate!.transitionSetup()
        toDelegate!.transitionSetup()
        let fromSnapshot = fromVC.view.snapshotView(afterScreenUpdates: true)!
        fromSnapshot.frame = fromVC.view.frame
        containerView.addSubview(fromSnapshot)

        // 6: Create to screen snapshot
        let toSnapshot = toVC.view.snapshotView(afterScreenUpdates: true)!
        toSnapshot.frame = fromVC.view.frame
        containerView.addSubview(toSnapshot)
        toSnapshot.alpha = 0

        // 7: Bring the image view to the front and get the final frame
        containerView.bringSubview(toFront: imageView)
        let toFrame = (self.toDelegate == nil) ? CGRect() : self.toDelegate!.imageWindowFrame()

        // 8: Animate change
        UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: .curveEaseOut, animations: {
            toSnapshot.alpha = 1
            imageView.frame = toFrame

        }, completion:{ [weak self] (finished) in
            self?.toDelegate!.transitionCleanup()
            self?.fromDelegate!.transitionCleanup()
            // 9: Remove transition views
            imageView.removeFromSuperview()
            fromSnapshot.removeFromSuperview()
            toSnapshot.removeFromSuperview()

            // 10: Complete transition
            if !transitionContext.transitionWasCancelled {
                containerView.addSubview(toVC.view)
            }
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
    }

And this is in the presenting viewController:

func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let imagePresentationViewController = (presented as! UINavigationController).topViewController as! ImagePresentationViewController
        self.transition.setupImageTransition( image: pickedImageForTransition!, imageType: nil,
                                              fromDelegate: self,
                                              toDelegate: imagePresentationViewController)
        return transition
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let imagePresentationViewController = (dismissed as! UINavigationController).topViewController as! ImagePresentationViewController
        transition.setupImageTransition( image: pickedImageForTransition!, imageType: .listsImage,
                                         fromDelegate: imagePresentationViewController,
                                         toDelegate: self)
        return transition
    }
alionthego
  • 8,508
  • 9
  • 52
  • 125
  • Have you tried .overFullScreen ? – Sina KH Jun 17 '18 at 10:30
  • that doesn't work. – alionthego Jun 17 '18 at 10:56
  • This may not be the issue but please note that every time you say something like `fromVC.view`, that is wrong. You should get the view using `view(forKey:)`. – matt Jun 17 '18 at 11:21
  • Also I may be missing something but where are your calls to `initialFrame` and `finalFrane`? You are not free to make up the frames, you must get them from the context. – matt Jun 17 '18 at 11:26
  • And I don’t see any code where you actually fulfill your responsibilities to get the to view controller view into the context and so forth. – matt Jun 17 '18 at 11:31
  • edited to show init – alionthego Jun 17 '18 at 13:09
  • this was from an online tutorial I did sometime ago. It works very well for the animated transition. just when I try to use overCurrentContext it comes back to a black screen – alionthego Jun 17 '18 at 13:13
  • There is a WWDC video on it, it might help https://developer.apple.com/videos/play/wwdc2014/228/ – user1046037 Jun 17 '18 at 16:14

1 Answers1

0

Had the same problem, you just need to remove container view from func animateTransition(using transitionContext: UIViewControllerContextTransitioning)

StaticV0id
  • 411
  • 4
  • 13