iOS 11 iPhone X模拟器UITabBar图标和标题顶部呈现在彼此之上

adr*_*hen 131 iphone uitabbar ios11 xcode9-beta iphone-x

任何人在UITabBar组件周围遇到iPhone X模拟器问题?

我似乎将图标和标题呈现在彼此之上,我不确定我是否遗漏了任何东西,我也在iPhone 8模拟器中运行它,以及一个看起来很好的实际设备,如图所示故事板.

iPhone X:

iPhone X UITabBar错误

iPhone 8

iPhone 8 UITabBar有效

小智 40

我只需在viewDidLayoutSubviews中的UITabBar上调用invalidateIntrinsicContentSize就可以解决这个问题.

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self.tabBar invalidateIntrinsicContentSize];
}
Run Code Online (Sandbox Code Playgroud)

注意:标签栏的底部需要包含在主视图的底部,而不是安全区域,并且标签栏应该没有高度约束.

  • 我还需要添加`[self.view layoutIfNeeded]`. (3认同)

Rai*_*kas 24

VoidLess提供的答案仅部分修复了TabBar问题.它修复了tabbar中的布局问题,但是如果你使用隐藏tabbar的viewcontroller,那么tabbar在动画期间会被错误地呈现(要重现它最好有2个segues - 一个模态和一个push.如果你交替segues,你可以看到标签栏被渲染出来了.下面的代码解决了这两个问题.好苹果.

class SafeAreaFixTabBar: UITabBar {

var oldSafeAreaInsets = UIEdgeInsets.zero

@available(iOS 11.0, *)
override func safeAreaInsetsDidChange() {
    super.safeAreaInsetsDidChange()

    if oldSafeAreaInsets != safeAreaInsets {
        oldSafeAreaInsets = safeAreaInsets

        invalidateIntrinsicContentSize()
        superview?.setNeedsLayout()
        superview?.layoutSubviews()
    }
}

override func sizeThatFits(_ size: CGSize) -> CGSize {
    var size = super.sizeThatFits(size)
    if #available(iOS 11.0, *) {
        let bottomInset = safeAreaInsets.bottom
        if bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90) {
            size.height += bottomInset
        }
    }
    return size
}

override var frame: CGRect {
    get {
        return super.frame
    }
    set {
        var tmp = newValue
        if let superview = superview, tmp.maxY != 
        superview.frame.height {
            tmp.origin.y = superview.frame.height - tmp.height
        }

        super.frame = tmp
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Objective-C代码:

@implementation VSTabBarFix {
    UIEdgeInsets oldSafeAreaInsets;
}


- (void)awakeFromNib {
    [super awakeFromNib];

    oldSafeAreaInsets = UIEdgeInsetsZero;
}


- (void)safeAreaInsetsDidChange {
    [super safeAreaInsetsDidChange];

    if (!UIEdgeInsetsEqualToEdgeInsets(oldSafeAreaInsets, self.safeAreaInsets)) {
        [self invalidateIntrinsicContentSize];

        if (self.superview) {
            [self.superview setNeedsLayout];
            [self.superview layoutSubviews];
        }
    }
}

- (CGSize)sizeThatFits:(CGSize)size {
    size = [super sizeThatFits:size];

    if (@available(iOS 11.0, *)) {
        float bottomInset = self.safeAreaInsets.bottom;
        if (bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90)) {
            size.height += bottomInset;
        }
    }

    return size;
}


- (void)setFrame:(CGRect)frame {
    if (self.superview) {
        if (frame.origin.y + frame.size.height != self.superview.frame.size.height) {
            frame.origin.y = self.superview.frame.size.height - frame.size.height;
        }
    }
    [super setFrame:frame];
}


@end
Run Code Online (Sandbox Code Playgroud)

  • 谢谢您的回答.但是如何在UITabBarController类中使用它? (4认同)
  • @Jojo,考虑到通过代码填充标签栏需要多少代码,我总是使用情节提要板创建uitabbarcontroller。在那里,您可以为标签栏分配自定义类。希望这可以帮助。 (2认同)

小智 21

有一个技巧可以解决问题.

只需将您的UITabBar放入UIView中即可.

这真的对我有用.

或者您可以按照此链接获取更多详细信息.

  • 这很好用,有一个简单包含UITabBar的uiview.将约束放在UIView(L,R和Bottom)上的安全区域,给它一个高度(49),并将UITabBar限制在UIView的四周. (3认同)
  • 此方法有效,但是“不安全”区域的颜色可能与选项卡栏的颜色不同(以防超级视图和选项卡栏的颜色不同) (2认同)

Cru*_*ruz 15

覆盖UITabBar sizeThatFits(_)safeArea

extension UITabBar {
    static let height: CGFloat = 49.0

    override open func sizeThatFits(_ size: CGSize) -> CGSize {
        guard let window = UIApplication.shared.keyWindow else {
            return super.sizeThatFits(size)
        }
        var sizeThatFits = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            sizeThatFits.height = UITabBar.height + window.safeAreaInsets.bottom
        } else {
            sizeThatFits.height = UITabBar.height
        }
        return sizeThatFits
    }
}
Run Code Online (Sandbox Code Playgroud)


aaa*_*jaa 10

我将此添加到viewWillAppear我的自定义中UITabBarController,因为所提供的答案都不适用于我:

tabBar.invalidateIntrinsicContentSize()
tabBar.superview?.setNeedsLayout()
tabBar.superview?.layoutSubviews()
Run Code Online (Sandbox Code Playgroud)


dee*_*eej 7

将标签栏从底部移开1点为我工作.

当然,你会因此而得到一个差距,你必须以某种方式填写,但文本/图标现在正确定位.


mol*_*ira 7

我有同样的问题.

在此输入图像描述

如果我在UITabBar的底部约束上将任何非零常量设置为安全区域:

在此输入图像描述

它按预期开始工作......

在此输入图像描述

这是我做出的唯一改变,我不知道为什么会有效,但如果有的话,我很想知道.


小智 5

通过使用子类UITabBar来应用safeAreaInsets:

class SafeAreaFixTabBar: UITabBar {

    var oldSafeAreaInsets = UIEdgeInsets.zero

    @available(iOS 11.0, *)
    override func safeAreaInsetsDidChange() {
        super.safeAreaInsetsDidChange()

        if oldSafeAreaInsets != safeAreaInsets {
            oldSafeAreaInsets = safeAreaInsets

            invalidateIntrinsicContentSize()
            superview?.setNeedsLayout()
            superview?.layoutSubviews()
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var size = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            let bottomInset = safeAreaInsets.bottom
            if bottomInset > 0 && size.height < 50 {
                size.height += bottomInset
            }
        }
        return size
    }
}
Run Code Online (Sandbox Code Playgroud)


Rya*_*anM 5

啊哈!这真的很神奇!

经过几个小时诅咒苹果后,我终于想到了这一点.

UIKit实际上确实为您处理了这个问题,并且看起来移位的标签栏项目是由于不正确的设置(可能是实际的UIKit错误).不需要子类化或背景视图.

如果UITabBar被限制在superview的底部,而不是底部安全区域,它将"正常工作" .

它甚至可以在Interface builder中使用.

正确设置

在IB工作

  1. 在界面构建器中,查看为iPhone X,将UITabBar拖动到它捕捉到底部安全区域插入的位置.当你放下它时,它看起来应该是正确的(将空间一直填充到底部边缘).
  2. 然后,您可以执行"添加缺失约束",IB将添加正确的约束,您的标签栏将神奇地适用于所有iPhone!(请注意,底部约束看起来像是一个等于iPhone X不安全区域高度的常量值,但常量实际上是0)

有时它仍然无效

IB中破了

真正愚蠢的是,即使你在上面的步骤中添加IB添加的确切约束,你也可以在IB中明确地看到错误!

  1. 拖出UITabBar并且不要将其捕捉到底部安全区域插入
  2. 将前导,尾随和底部约束全部添加到superview(非安全区域)奇怪的是,如果在约束检查器中为底部约束执行"反向第一和第二项",这将自行修复._(ツ)_ /¯


A.B*_*ger 2

UITabBar 的高度增加到主页按钮/线上方,但在其原始位置绘制子视图并将 UITabBarItem 覆盖在子视图上。

作为解决方法,您可以检测 iPhone X,然后将视图高度缩小 32px,以确保选项卡栏显示在主线上方的安全区域中。

例如,如果您正在以编程方式创建 TabBar,请替换

self.tabBarController = [[UITabBarController alloc] init];
self.window.rootViewController = self.tabBarController;
Run Code Online (Sandbox Code Playgroud)

有了这个:

#define IS_IPHONEX (([[UIScreen mainScreen] bounds].size.height-812)?NO:YES)
self.tabBarController = [[UITabBarController alloc] init];    
self.window.rootViewController = [[UIViewController alloc] init] ;
if(IS_IPHONEX)
    self.window.rootViewController.view.frame = CGRectMake(self.window.rootViewController.view.frame.origin.x, self.window.rootViewController.view.frame.origin.y, self.window.rootViewController.view.frame.size.width, self.window.rootViewController.view.frame.size.height + 32) ;
[self.window.rootViewController.view addSubview:self.tabBarController.view];
self.tabBarController.tabBar.barTintColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;
self.window.rootViewController.view.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;
Run Code Online (Sandbox Code Playgroud)

注意:这很可能是一个错误,因为视图大小和选项卡栏布局是由操作系统设置的。它可能应该按照 Apple 在 iPhone X 人机界面指南中的屏幕截图显示:https ://developer.apple.com/ios/ human-interface-guidelines/overview/iphone-x/