iOS10下ViewController中UIView布局错位,iOS11正常的技术求助
Hey there, let's break down why your bottom constraint is misbehaving on iOS 10 but works fine on iOS 11, and how to fix it—since your go-to viewDidLayoutSubviews() approach isn't working this time around.
The Root Cause: iOS 11's Layout Guide Overhaul
Apple introduced safeAreaLayoutGuide in iOS 11 to replace the older topLayoutGuide and bottomLayoutGuide. If your bottom constraint is directly tied to the superview's bottom anchor instead of adapting to these system layout guides, iOS 10 will miscalculate the offset. The old guides handle system bars (like tab bars or navigation bars) differently than the safe area, leading to that upward shift you're seeing.
Solutions to Try
1. Build Version-Aware Constraints from the Start
Instead of patching constraints after layout, create adaptive constraints that work across iOS versions. This is more reliable than post-layout resets:
override func viewDidLoad() { super.viewDidLoad() // Assume your main content view is stored as `mainContentView` mainContentView.translatesAutoresizingMaskIntoConstraints = false // Pin leading, trailing, and top anchors normally NSLayoutConstraint.activate([ mainContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor), mainContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor), mainContentView.topAnchor.constraint(equalTo: view.topAnchor) ]) // Handle bottom constraint with OS version check if #available(iOS 11.0, *) { let bottomConstraint = mainContentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) NSLayoutConstraint.activate([bottomConstraint]) } else { let bottomConstraint = mainContentView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.bottomAnchor) NSLayoutConstraint.activate([bottomConstraint]) } }
2. Debug Storyboard/XIB Constraints
If you set up constraints visually:
- Double-check if your bottom constraint is linked to
Superview.Bottominstead ofBottom Layout Guide.Top(for iOS 10) orSafe Area.Bottom(for iOS 11). - Add two separate bottom constraints: one tied to the old layout guide (active for iOS ≤10) and one tied to the safe area (active for iOS ≥11), then toggle their active status via code or Storyboard's "Installed" conditions.
3. Fix the viewDidLayoutSubviews() Approach
If you still want to use this method, update the constraint's anchor (not just the constant) and force an immediate layout refresh:
// Store your bottom constraint as a class property first private var bottomConstraint: NSLayoutConstraint! override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // Only run this logic for iOS 10 and below guard #available(iOS 10.0, *), !#available(iOS 11.0, *) else { return } // Deactivate the old constraint and replace it bottomConstraint.isActive = false bottomConstraint = mainContentView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.bottomAnchor) bottomConstraint.isActive = true view.layoutIfNeeded() // Force the layout to update right away }
4. Check the "Adjust Scroll View Insets" Setting
If your view controller is embedded in a navigation or tab bar controller, disable the Adjust Scroll View Insets option in your view controller's attributes inspector. iOS 10 and 11 handle this setting differently, which can cause unexpected layout shifts even for non-scroll views.
内容的提问来源于stack exchange,提问作者Vlad Stefan

