containerView的自定义动画中的modalPresentationStyle .overCurrentContext返回黑屏

Posted

技术标签:

【中文标题】containerView的自定义动画中的modalPresentationStyle .overCurrentContext返回黑屏【英文标题】:modalPresentationStyle .overCurrentContext in custom animation of a containerView returns to black screen 【发布时间】:2018-06-17 10:11:46 【问题描述】:

我在另一个 viewController 的 containerView 中有一个 tableViewController。

当点击图像时,会发生自定义转换到另一个 viewController 以查看图像。过渡效果很好。

当自定义转换发生时,虽然在 containerView 的 tableViewController 上调用了 viewWillDisappear,然后当呈现的 viewController 被关闭时再次调用 viewWillAppear(再次使用转换)。

这会导致 tableView 中偶尔出现一些异常滚动。

我想要为 imageViewer 呈现一个过渡但 overCurrentContext。

我已经尝试过人们的建议如下:

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

不幸的是,这不起作用,当 imageViewController 被解除时,最初的过渡是正确的,并且可以看到 tableViewController。但是一旦过渡完成,视图就会变黑。

我认为这可能与我使用的是 containerView 的事实有关。但不确定也不知道如何解决。

这是我正在使用的动画方法:

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)
        )
    

这是在呈现的 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
    

【问题讨论】:

你试过 .overFullScreen 吗? 那行不通。 这可能不是问题,但请注意,每次你说fromVC.view 之类的东西时,这是错误的。您应该使用view(forKey:) 获取视图。 我也可能遗漏了一些东西,但是您对initialFramefinalFrane 的电话在哪里?你不能随意编框架,你必须从上下文中获取它们。 而且我没有看到任何代码让您真正履行职责以将视图控制器视图放入上下文等。 【参考方案1】:

遇到同样的问题,你只需要从func animateTransition(using transitionContext: UIViewControllerContextTransitioning)中删除容器视图

【讨论】:

以上是关于containerView的自定义动画中的modalPresentationStyle .overCurrentContext返回黑屏的主要内容,如果未能解决你的问题,请参考以下文章

SceneKit 中的自定义动画属性

UICollectionViewFlowLayout 中的自定义动画 - 水平滚动方向

当我将 UIView 动画放在不同类的 containerView 中时,为啥我的 UIView 动画不起作用?

DragonBones龙骨骨骼中的自定义事件(另有声音动画事件)

如何将 UINavigationControllerDelegate 中的自定义过渡动画应用于特定的推送和弹出事件?

我的轮播和我的自定义动画中的问题