iOS 10与iOS 11/12安全区适配:Objective-C iPad应用布局异常
这个问题我太熟了!确实是iOS 11引入的安全区(Safe Area)机制搞的鬼——UIToolbar在iOS 11及以后版本会自动适配安全区,所以底部会留出那20px左右的空白(非刘海屏设备的底部安全区高度),但iOS 10里它是老老实实紧贴屏幕底部的。要实现跨版本的一致布局,给你几个靠谱的方案:
方案一:强制Toolbar忽略安全区(最推荐)
从iOS 11开始,UIView新增了safeAreaLayoutGuide属性,UIToolbar默认会依赖它来布局。我们可以直接让Toolbar跳过安全区,紧贴屏幕底部:
纯代码实现(Objective-C)
如果你的布局是纯代码写的,先确保Toolbar关闭自动转约束,然后直接把底部约束关联到父视图的底部,而非安全区:
// 假设toolbar是你的UIToolbar实例,self.view为父视图 toolbar.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [toolbar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [toolbar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [toolbar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], // 关键:关联到view的bottom,不是safeArea [toolbar.heightAnchor constraintEqualToConstant:44] // 固定Toolbar高度,按需添加 ]];
如果之前用的是Autoresizing Mask布局,记得在iOS 11+系统里关闭安全区边距适配:
toolbar.translatesAutoresizingMaskIntoConstraints = YES; toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; // iOS 11及以上单独处理 if (@available(iOS 11.0, *)) { toolbar.insetsLayoutMarginsFromSafeArea = NO; }
Storyboard/Xib可视化实现
如果是用可视化布局,选中Toolbar后:
- 在右侧属性面板里找到Safe Area Relative Margins,取消勾选;
- 添加底部约束时,选择关联到父视图的
Bottom,而不是Safe Area Bottom。
方案二:调整上方内容避开Toolbar
如果你不想动Toolbar的位置,而是让上方的图片/流内容不侵入Toolbar,可以针对不同系统版本调整内容的底部约束:
- iOS 10及以下:让内容底部贴Toolbar顶部;
- iOS 11及以上:让内容底部贴安全区底部(此时Toolbar在安全区上方,自然不会被侵入)。
代码示例:
// 假设contentView是你的上方内容视图 UIView *targetBottomAnchor = self.view.bottomAnchor; if (@available(iOS 11.0, *)) { targetBottomAnchor = self.view.safeAreaLayoutGuide.bottomAnchor; } [contentView.bottomAnchor constraintEqualToAnchor:targetBottomAnchor].active = YES;
不过这个方案会让iOS 11+的内容和Toolbar之间没有重叠,但Toolbar下方的黑块(安全区)依然存在,可能不是你想要的最终效果,所以优先选方案一。
方案三:用内边距抵消安全区影响
还有一种方式是针对iOS 11+,给Toolbar设置负的底部约束,把它“拉”回屏幕底部:
if (@available(iOS 11.0, *)) { CGFloat bottomSafeHeight = self.view.safeAreaInsets.bottom; [toolbar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:bottomSafeHeight].active = YES; } else { [toolbar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; }
但这种方式可能会让Toolbar的底部被屏幕边缘遮挡(比如有底部安全区的设备),所以不如方案一稳妥。
修改完之后记得在iOS 10和iOS 11+的模拟器里分别测试,就能看到Toolbar都紧贴屏幕底部,上方内容刚好延伸到Toolbar顶部,和iOS 10的原有效果完全一致啦!
内容的提问来源于stack exchange,提问作者Jerry Dubuke

