【问题标题】:ios 11 UITabBar UITabBarItem positioning issueios 11 UITabBar UITabBarItem 定位问题
【发布时间】:2017-12-03 00:04:14
【问题描述】:

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

iOS 10+

iOS 11

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

【问题讨论】:

  • 这是一个功能,而不是一个错误。
  • 这不仅仅是objective-c的问题,一般来说objective-c和swift应用程序都有。
  • 功能?身份证。更多的是苹果“改进”某事而不考虑所有后果的案例。
  • 有什么后果。只有当有足够的空间时,它才会这样工作。 Apple 关心一切……这是一项功能。我们应该为此给他们买一瓶酒;)现在有更多的空间可以与用户互动。空间现已完全可用。

标签: ios objective-c uitabbar uitabbaritem ios11


【解决方案1】:

我正在维护一个主要用 Objective-C 编写的大型 iPad 应用程序,该应用程序已在多个 iOS 版本中幸存下来。我遇到了这样一种情况,即我需要 iOS 11 之前的标签栏外观(图标在标题上方而不是在它们旁边)用于几个标签栏。我的解决方案是创建一个覆盖 traitCollection 方法的 UITabBar 的子类,以便它始终返回一个水平紧凑的特征集合。这会导致 iOS 11 在所有标签栏按钮的图标下方显示标题。

为了使用它,将故事板中标签栏的自定义类设置为这个新的子类,并将代码中指向标签栏的所有出口更改为这种新类型(不要忘记导入下面的头文件)。

在这种情况下,.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

【讨论】:

  • 我不使用故事板/IB,但通过继承 UITabBarController 而不是 UITabBar 并覆盖相同的 traitCollection 方法,我能够获得完全相同的效果。
  • 实际上从头开始。不推荐子类化 UITabBarController,事实上导航栏在 iOS 11 GM 中被破坏了。
  • 不幸的是,这样做会破坏导航栏的外观(UIBarButtonItems 和导航栏标题):forums.developer.apple.com/thread/86013
  • @NikoZarzani 仅当您继承 UITabBarController 时,它才会破坏导航栏的外观。如果您将 UITabBar 子类化,导航栏的外观将保持原样。
  • 遗憾的是,在 iOS 13 中,这开始产生此警告 Class MyClass overrides the -traitCollection getter, which is not supported. If you're trying to override traits, you must use the appropriate API.
【解决方案2】:

根据 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
    }
}

【讨论】:

  • 不推荐这样做,尽管我现在听到它有效并不感到惊讶。如果UITabBar 也覆盖traitCollection,和/或如果UITabBar 上有另一个扩展(或Objective-C 类别)在某处实现它,那么结果是未定义的。你最好继承子类(这很烦人)。请参阅stackoverflow.com/questions/5267034/category-conflicts 了解更多信息。
  • @nolanw 如果您只使用UITabBarController,有没有办法使用子类?注意:这个答案在这种情况下也有效。
  • @DanRosenstark 是的:使用故事板。我在一个项目中有一个故事板,它有一个普通的UITabBarController,其唯一的自定义是设置其标签栏的类,然后我在代码中加载它。这让人头疼,但它比 swizzling 更安全,也比 hopping 更安全,没有类别冲突。
  • @nolanw 您还可以使用带有标签栏控制器的单独 xib 文件作为该 xib 布局中的根视图。然后用Bundle.main.loadNibNamed("MyTabBarController", owner: nil, options: [])?.first加载标签栏控制器
【解决方案3】:

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

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

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

【讨论】:

  • 这确实更好!
  • 太棒了..这对我有用。当我刚刚为特征集合设置了紧凑尺寸类时,它修复了我的标签栏项目,但破坏了我的导航栏按钮。谢谢!!
  • @BharatRaichur 子类 UITabBar 不是 UITabBarController 然后覆盖 - (UITraitCollection *)traitCollection{...}。这不会破坏您的导航栏。
  • iOS 13 在控制台中吐出大量关于此解决方案修复的特征的调试。尽管“[TraitCollection] 类 CustomiPadUITabBar 覆盖了不支持的 -traitCollection getter,但仍报告了一个错误。如果您尝试覆盖特征,则必须使用适当的 API。”。任何想法如何摆脱那个?是否有“适当的 API”?
【解决方案4】:

注意: This fix above 似乎工作得很好。不知道它在未来会如何运作,但目前它运作良好。


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

  • iPhone 横屏
  • 一直都是 iPad

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

我们为标签栏提供了这种全新的外观,无论是在横向还是在 iPad 上,我们都可以并排显示图标和文本。特别是在 iPhone 上,图标更小,标签栏更小,以便在垂直方向留出更多空间。

【讨论】:

    【解决方案5】:

    带有避免扩展/类别命名冲突的子类的 Swift 4 版本:

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

    如果您使用 Interface Builder 和 storyboards,您可以在 UITabBarController 场景中选择标签栏视图,然后在 Identity Inspector 中将其类更改为 TabBar

    【讨论】:

      【解决方案6】:

      除了约翰的回答:

      如果您有超过 4 个标签栏项目并且不想要“更多”按钮,则必须采用不同的尺寸等级。如果您想要项目的原始居中布局,则必须添加另一种方法,如下所示:

      #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
      

      【讨论】:

      • 这个解决方案刹车导航栏图标:(
      【解决方案7】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-23
        • 2019-11-22
        • 1970-01-01
        • 2015-01-24
        • 2018-03-06
        相关资源
        最近更新 更多