自定义Zoom转场后返回NavigationController栈出现黑屏问题求助
Hey there, let's dig into why you're getting that black screen when popping back to your TableView. First off, I notice your animateTransition method is cut off at the else clause for the dismiss/pop case — that's a big red flag. But even beyond that, there are a few key gaps in your transition logic that are causing this problem. Let's break it down step by step:
1. Your pop transition code is incomplete
You started writing the logic for handling the .pop operation, but never finished configuring the animation or wrapping up the transition properly. This leaves the view hierarchy in an inconsistent state, leading to the black screen.
2. You're missing the critical transition completion call
No matter if you're pushing or popping, you must tell the system when the transition is finished with transitionContext.completeTransition(). Without this call, the navigation controller doesn't update its internal view state, so it doesn't know to show your original TableView after the pop.
3. Pop transition view state fixes
For the pop case, you need to properly set up the initial state of both views before the animation, and update their transforms/alpha values during the animation. Here's how to fix and complete your code:
Full corrected animateTransition method
I've filled in the missing pop logic and added the required completion call:
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let presenting = operation == .push let containerView = transitionContext.containerView guard let toView = transitionContext.view(forKey: .to) else { return } guard let fromView = transitionContext.view(forKey: .from) else { return } let storyFeedView = presenting ? fromView : toView let storyDetailView = presenting ? toView : fromView var initialFrame = presenting ? thumbnailFrame : storyDetailView.frame let finalFrame = presenting ? storyDetailView.frame : thumbnailFrame // Keep your existing aspect ratio calculation logic let initialFrameAspectRatio = initialFrame.width / initialFrame.height let storyDetailAspectRatio = storyDetailView.frame.width / storyDetailView.frame.height if initialFrameAspectRatio > storyDetailAspectRatio { initialFrame.size = CGSize(width: initialFrame.height * storyDetailAspectRatio, height: initialFrame.height) } else { initialFrame.size = CGSize(width: initialFrame.width, height: initialFrame.width / storyDetailAspectRatio) } let finalFrameAspectRatio = finalFrame.width / finalFrame.height var resizedFinalFrame = finalFrame if finalFrameAspectRatio > storyDetailAspectRatio { resizedFinalFrame.size = CGSize(width: finalFrame.height * storyDetailAspectRatio, height: finalFrame.height) } else { resizedFinalFrame.size = CGSize(width: finalFrame.width, height: finalFrame.width / storyDetailAspectRatio) } let scaleFactor = resizedFinalFrame.width / initialFrame.width let growScaleFactor = presenting ? scaleFactor : 1/scaleFactor let shrinkScaleFactor = 1/growScaleFactor // Set initial view states for both push and pop if presenting { storyDetailView.transform = CGAffineTransform(scaleX: shrinkScaleFactor, y: shrinkScaleFactor) storyDetailView.center = CGPoint(x: thumbnailFrame.midX, y: thumbnailFrame.midY) storyDetailView.clipsToBounds = true } else { // Configure initial state for pop transition storyFeedView.transform = CGAffineTransform(scaleX: growScaleFactor, y: growScaleFactor) storyFeedView.transform = storyFeedView.transform.translatedBy(x: storyFeedView.frame.midX - thumbnailFrame.midX, y: storyFeedView.frame.midY - thumbnailFrame.midY) storyDetailView.center = CGPoint(x: thumbnailFrame.midX, y: thumbnailFrame.midY) storyDetailView.clipsToBounds = true } storyDetailView.alpha = presenting ? 0 : 1 storyFeedView.alpha = presenting ? 1 : 0 // Manage view hierarchy correctly for both transitions if presenting { containerView.addSubview(toView) containerView.bringSubview(toFront: storyDetailView) } else { // Insert TableView behind detail view so it's visible when detail fades out containerView.insertSubview(toView, belowSubview: storyDetailView) } // Animate the transition UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 1.0, options: [.curveEaseInOut], animations: { storyDetailView.alpha = presenting ? 1 : 0 storyFeedView.alpha = presenting ? 0 : 1 if presenting { let scale = CGAffineTransform(scaleX: growScaleFactor, y: growScaleFactor) let translate = storyFeedView.transform.translatedBy(x: storyFeedView.frame.midX - self.thumbnailFrame.midX, y: storyFeedView.frame.midY - self.thumbnailFrame.midY) storyFeedView.transform = translate.concatenating(scale) storyDetailView.transform = .identity } else { // Reset TableView to original state, shrink detail view to thumbnail storyFeedView.transform = .identity storyDetailView.transform = CGAffineTransform(scaleX: shrinkScaleFactor, y: shrinkScaleFactor) } }) { _ in // Critical: notify system transition is complete transitionContext.completeTransition(!transitionContext.transitionWasCancelled) // Reset transforms if transition was cancelled to avoid stuck views if !transitionContext.transitionWasCancelled { storyFeedView.transform = .identity storyDetailView.transform = .identity } } }
Additional quick checks
- Double-check that you're passing the correct
thumbnailFramewhen triggering the pop transition — it should match the exact frame of the original TableView cell (convert it to the container view's coordinate space if needed) - Confirm your navigation controller's delegate is properly set, and that you're returning this animator for both
.pushand.popoperations
The main culprits here were the incomplete pop animation logic and missing the completeTransition call — adding those should fix the black screen issue entirely.
内容的提问来源于stack exchange,提问作者Nicolai Harbo

