Navigation controller top layout guide not honored with custom transition

前端 未结 12 1502
暖寄归人
暖寄归人 2020-12-04 11:35

Short version:

I am having a problem with auto layout top layout guide when used in conjunction with custom transition and UINavigationController in iO

相关标签:
12条回答
  • 2020-12-04 11:36

    I struggled with the exact same problem. Putting this in the viewDidLoad of my toViewController really helped me out:

    self.edgesForExtendedLayout = UIRectEdgeNone;
    

    This did not solve all my issues and I'm still looking for a better approach, but this certainly made it a bit easier.

    0 讨论(0)
  • 2020-12-04 11:37

    Just put the following code toviewDidLoad

    self.extendedLayoutIncludesOpaqueBars = YES;
    
    0 讨论(0)
  • 2020-12-04 11:38

    I ran into this same issue but without using a UINavigationController and just positioning a view off of the topLayoutGuide. The layout would be correct when first displayed, a transition would take place to another view, and then upon exiting and returning to the first view, the layout would be broken as that topLayoutGuide would no longer be there.

    I solved this problem by capturing the safe area insets prior to the transition and then reimplementing them, not by adjusting my constraints, but by setting them on the viewController's additionalSafeAreaInsets.

    I found this solution to work well as I don't have to adjust any of my layout code and search through constraints and I can just reimplementing the space that was there previously. This could be more difficult if you are actually using the additionalSafeAreaInsets property.

    Example

    I added a variable to my transitionManager to capture the safe insets that exist when the transitionManager is created.

    class MyTransitionManager: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
    
        private var presenting = true
        private var container:UIView?
        private var safeInsets:UIEdgeInsets?
    
        ...
    

    Then during the entering transition I save those insets.

        let toView = viewControllers.to.view
        let fromView = viewControllers.from.view
    
        if #available(iOS 11.0, *) {
            safeInsets = toView.safeAreaInsets
        }
    

    In the case of the iPhone X this looks something like UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

    Now when exiting, the insets on that same view we transitioned from in the entrance will be .zero so we add our captured insets to the additionalSafeAreaInsets on the viewController, which will set them on our view for us as well as update the layout. Once our animation is done, we reset the additionalSafeAreaInsets back to .zero.

        if #available(iOS 11.0, *) {
            if safeInsets != nil {
                viewControllers.to.additionalSafeAreaInsets = safeInsets!
            }
        }
    
        ...then in the animation completion block
    
        if #available(iOS 11.0, *) {
            if self.safeInsets != nil {
                viewControllers.to.additionalSafeAreaInsets = .zero
            }
        }
    
        transitionContext.completeTransition(true)
    
    0 讨论(0)
  • 2020-12-04 11:42

    try :

    self.edgesforextendedlayout=UIRectEdgeNone
    

    Or just set navigationbar opaque and set background image or backgroundcolor to navigationbar

    0 讨论(0)
  • 2020-12-04 11:45

    I had the same problem, ended up implementing my own topLayout guide view and making constraints to it rather then to topLayoutGuide. Not ideal. Only posting it here in case someone is stuck and looking for quick hacky solution http://www.github.com/stringcode86/SCTopLayoutGuide

    0 讨论(0)
  • 2020-12-04 11:46

    I solved this by fixing the height constraint of the topLayoutGuide. Adjusting edgesForExtendedLayout wasn't an option for me, as I needed the destination view to underlap the navigation bar, but also to be able to layout subviews using topLayoutGuide.

    Directly inspecting the constraints in play shows that iOS adds a height constraint to the topLayoutGuide with value equal to the height of the navigation bar of the navigation controller. Except, in iOS 7, using a custom animation transition leaves the constraint with a height of 0. They fixed this in iOS 8.

    This is the solution I came up with to correct the constraint (it's in Swift but the equivalent should work in Obj-C). I've tested that it works on iOS 7 and 8.

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let fromView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!.view
        let destinationVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
        destinationVC.view.frame = transitionContext.finalFrameForViewController(destinationVC)
        let container = transitionContext.containerView()
        container.addSubview(destinationVC.view)
    
        // Custom transitions break topLayoutGuide in iOS 7, fix its constraint
        if let navController = destinationVC.navigationController {
            for constraint in destinationVC.view.constraints() as [NSLayoutConstraint] {
                if constraint.firstItem === destinationVC.topLayoutGuide
                    && constraint.firstAttribute == .Height
                    && constraint.secondItem == nil
                    && constraint.constant == 0 {
                    constraint.constant = navController.navigationBar.frame.height
                }
            }
        }
    
        // Perform your transition animation here ...
    }
    
    0 讨论(0)
提交回复
热议问题