ios 11 UITabBar UITabBarItem定位问题

ios 11 UITabBar UITabBarItem positioning issue

我使用新的 Xcode 9 beta for ios 11 构建了我的应用程序。我发现 UITabBar 存在问题,其中项目分布在 UITabBar 中并且标题与图像右对齐。我曾尝试更改代码以使其正常工作,但仍未成功。

ios 10+

ios11

我可以使用 tabBarItem.titlePositionAdjustment 更改标题的位置 但这不是我的要求,因为它应该自动出现在图像本身下方。我尝试设置 tabbar.itemPositioning to UITabBarItemPositioningCentered,也尝试更改 itemSpacingwidth,但仍然没有用。有人可以帮助我理解为什么会发生这种情况以及如何解决这个问题吗?我希望它喜欢 ios 10+ 版本并且图像是从 iPad.

的最左角拍摄的

注意: 似乎工作得很好。不确定它将来会如何工作,但目前它工作得很好。


根据 this WWDC talk,这是以下的新行为:

  • iPhone 横向
  • iPad一直

如果我没看错的话,这个行为是无法改变的:

We've got this brand new appearance for the tab bar, both in landscape and on iPad, where we show the icon and the text side by side. And in particular on iPhones the icon is smaller and the tab bar is smaller to give a bit more room vertically.

我正在维护一个主要用 Objective-C 编写的大型 iPad 应用程序,该应用程序已经存在了几个 iOS 版本。我 运行 遇到了我需要 pre-iOS 11 标签栏外观 运行ce(图标在标题上方而不是旁边)的情况,用于几个标签栏。我的解决方案是创建一个 UITabBar 的子 class 来覆盖 traitCollection 方法,以便它始终 returns 一个 horizontally-compact 特征 collection。这会导致 iOS 11 在所有标签栏按钮的图标下方显示标题。

为了使用它,将情节提要中标签栏的自定义 class 设置为这个新子 class 并将代码中指向标签栏的任何出口更改为这种新类型(不要忘记导入下面的 header 文件)。

在这种情况下,.h 文件几乎是空的:

//
//  MyTabBar.h
//

#import <UIKit/UIKit.h>

@interface MyTabBar : UITabBar

@end

这是实现了 traitCollection 方法的 .m 文件:

//
//  MyTabBar.m
//

#import "MyTabBar.h"

@implementation MyTabBar

// In iOS 11, UITabBarItem's have the title to the right of the icon in horizontally regular environments
// (i.e. the iPad).  In order to keep the title below the icon, it was necessary to subclass UITabBar and override
// traitCollection to make it horizontally compact.

- (UITraitCollection *)traitCollection {
    return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
}

@end

除了约翰的回答:

如果您有 4 个以上的标签栏项目并且不想要 "More" 按钮,您必须采用不同的尺寸 Class。如果你想要项目的原始居中布局,你必须添加另一种方法,如下所示:

#import "PreIOS11TabBarController.h"

@interface PreIOS11TabBarController ()

@end

@implementation PreIOS11TabBarController

// In iOS 11, UITabBarItem's have the title to the right of the icon in horizontally regular environments
// (i.e. the iPad).  In order to keep the title below the icon, it was necessary to subclass UITabBar and override
// traitCollection to make it horizontally compact.

- (UITraitCollection *)traitCollection {
    return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassUnspecified];
}


- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    self.tabBar.itemPositioning = UITabBarItemPositioningCentered;
}

@end

为了避免弄乱任何其他特征,与超类结合不是更好吗:

- (UITraitCollection *)traitCollection
{
  UITraitCollection *curr = [super traitCollection];
  UITraitCollection *compact = [UITraitCollection  traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];

  return [UITraitCollection traitCollectionWithTraitsFromCollections:@[curr, compact]];
}

根据 John C 的回答,这里是 Swift 3 版本,无需 Storyboard 或子类化即可以编程方式使用:

extension UITabBar {
    // Workaround for iOS 11's new UITabBar behavior where on iPad, the UITabBar inside
    // the Master view controller shows the UITabBarItem icon next to the text
    override open var traitCollection: UITraitCollection {
        if UIDevice.current.userInterfaceIdiom == .pad {
            return UITraitCollection(horizontalSizeClass: .compact)
        }
        return super.traitCollection
    }
}

Swift 4 版本带有子 class 避免 extension/category 命名冲突:

class TabBar: UITabBar {
  override var traitCollection: UITraitCollection {
    guard UIDevice.current.userInterfaceIdiom == .pad else {
      return super.traitCollection
    }

    return UITraitCollection(horizontalSizeClass: .compact)
  }
}

如果您使用 Interface Builder 和故事板,您可以 select 在您的 UITabBarController 场景中的选项卡栏视图,并在身份检查器中将其 class 更改为 TabBar :

@massimobio 的 answer 很好,但是它导致大导航栏标题对我来说消失了。尚未进一步调查此问题,但这似乎可以解决问题:

override var traitCollection: UITraitCollection {
        guard UIDevice.current.userInterfaceIdiom == .pad else {
            return super.traitCollection
        }

        return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(horizontalSizeClass: .compact)])
    }

Max Desiatov 的回答部分有效。 它与 light/dark 模式混淆。

这是另一个解决方案,它不会干扰主要的 traitCollection,但可以协同工作。

class CompactTabBar: UITabBar {
    
    override var traitCollection: UITraitCollection {
        guard UIDevice.current.userInterfaceIdiom == .pad else {
            return super.traitCollection
        }
        
        let compactTrait = UITraitCollection(horizontalSizeClass: .compact)
        let tabTrait = UITraitCollection(traitsFrom: [super.traitCollection, compactTrait])
        
        return tabTrait
    }
}

只需将此 class 分配给 UIStoryboard 中 UITabBarController 的 UITabBar 对象。