【问题标题】:UINavigationController embedded in a container view, displays a Table View Controller with wrong sizeUINavigationController 嵌入在容器视图中,显示大小错误的 Table View Controller
【发布时间】:2015-04-20 22:36:15
【问题描述】:

我正在尝试找到解决这种情况的方法:
我有一个 UITabBarController,其 segue 之一连接到我用来嵌入 UINavigationController 的容器视图控制器 (BannerViewController),导航控制器推送其他容器视图控制器 (EventListContainerviewController),每个容器视图控制器都包含一个 tableview 控制器。
这是我故事板的屏幕
问题是最后一个容器视图显示在比它们的容器更小的框架中。似乎他们松开了底部的标签栏空间。
我已经强制所有视图控制器、导航控制器和标签栏控制器避免不扩展它们的边缘并调整插图。

颜色表示:

红色:BannerContainerViewController 的主视图 0x7fcc6d38bb00
浅绿色:BannerContainerViewController 的容器视图 0x7fcc6d38b860

蓝色:EventListContainerViewController 的主视图 0x7fcc6bd7b7c0
橙色:EventListContainerViewController 的容器视图 0x7fcc6bd7b690

当导航控制器添加蓝色容器视图时,似乎发生了一些变化,将其大小减小了相同数量的标签栏(49pt)。 在视图层次结构的递归描述中也可以看出:

<UIWindow: 0x7fcc6bd5af40; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7fcc6bd4dd80>; layer = <UIWindowLayer: 0x7fcc6bd317c0>>
   | <UILayoutContainerView: 0x7fcc6bd671c0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcc6bd66de0>>
   |    | <UITransitionView: 0x7fcc6bd6a980; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7fcc6bd6ace0>>
   |    |    | <UIViewControllerWrapperView: 0x7fcc6d3a7b20; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcc6d3a7db0>>
   |    |    |    | <UIView: 0x7fcc6d38bb00; frame = (0 0; 320 519); autoresize = W+H; layer = <CALayer: 0x7fcc6d38bbd0>>
   |    |    |    |    | <UIView: 0x7fcc6d38b860; frame = (0 0; 320 519); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fcc6d38b930>>
   |    |    |    |    |    | <UILayoutContainerView: 0x7fcc6d398000; frame = (0 0; 320 519); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fcc6d3a4b50>; layer = <CALayer: 0x7fcc6d387670>>
   |    |    |    |    |    |    | <UINavigationTransitionView: 0x7fcc6d39cfa0; frame = (0 0; 320 519); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7fcc6d39cc40>>
   |    |    |    |    |    |    |    | <UIViewControllerWrapperView: 0x7fcc6bf31230; frame = (0 0; 320 519); autoresize = W+H; layer = <CALayer: 0x7fcc6bf31300>>
   |    |    |    |    |    |    |    |    | <UIView: 0x7fcc6bd7b7c0; frame = (0 64; 320 406); autoresize = W+H; layer = <CALayer: 0x7fcc6bd7afe0>>
   |    |    |    |    |    |    |    |    |    | <UIView: 0x7fcc6bd7b690; frame = (0 0; 320 406); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fcc6bd7aac0>>
   |    |    |    |    |    |    |    |    |    |    | <UITableView: 0x7fcc6f03c400; frame = (0 0; 320 406); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fcc6bf34aa0>; layer = <CALayer: 0x7fcc6bf30bc0>; contentOffset: {0, 0}; contentSize: {320, 170}>
   |    |    |    |    |    |    |    |    |    |    |    | <UITableViewWrapperView: 0x7fcc6bf35960; frame = (0 0; 320 406); gestureRecognizers = <NSArray: 0x7fcc6bf363e0>; layer = <CALayer: 0x7fcc6bf35ed0>; contentOffset: {0, 0}; contentSize: {320, 406}>
   |    |    |    |    |    |    |    |    |    |    |    |    | <EventCell: 0x7fcc6bca2950; baseClass = UITableViewCell; frame = (0 85; 320 85); autoresize = W; layer = <CALayer: 0x7fcc6bca2ca0>>

我尝试使用自定义 segue 而不是容器视图尝试强制布局,但我猜是导航控制器故障。
如您所见,横幅并未按预期与视图重叠。

有什么建议吗?

【问题讨论】:

  • 您是否检查过您的视图控制器是否检查了Extend Edges UnderBottomBars
  • 当然,正如我在问题中所写的那样
  • ops...他们都有未选中的扩展边缘
  • @las 似乎已经解决了这个问题。如果我将 BannerViewController 设置为扩展底部栏,框架是正确的,但我不明白为什么,这似乎是一个技巧而不是解决方案
  • 我不敢相信其他人也有这个特定的问题,我很难解决这个问题,真的很高兴我找到了这篇文章并看到这是一个已知问题

标签: ios objective-c uitableview uicontainerview


【解决方案1】:

这个问题在 iOS 10 中仍然存在。嵌入在容器视图中的 UINavigationController 又包含在 UITabBarController 中,将在导航堆栈中布置所有视图,并在底部为“幻像”标签栏留出额外空间.

最简单的解决方案是继承 UINavigationController 并从 tabBarController 返回“nil”。

class MyNavigationController: UINavigationController {

    override var tabBarController: UITabBarController? {
        return nil
    }

}

这使得导航堆栈中的视图认为它们没有标签栏控制器,因此它们在布局期间不会为它留下额外的空间。我没有注意到此修复有任何负面影响,但显然此导航控制器堆栈中的视图将不再有权访问选项卡栏控制器。如果这是一个问题,您可以使用更通用的方法来查找标签栏控制器(或任何“父”视图控制器)。

例如,如果您的应用程序的主视图控制器是名为“MainViewController”的 UITabBarController,您可以使用方便的方法扩展 UIViewController 来找到它。

extension UIViewController {

    func mainViewController() -> MainViewController? {
        var vc: UIViewController? = self
        while !(vc is MainViewController) && vc != nil {
            vc = vc?.parent ?? vc?.navigationController ?? vc?.presentingViewController
        }
        return vc as? MainViewController
    }

}

这是因为标签栏控制器是其直接子视图控制器的parent。上面的方法沿着父、展示和导航控制器链向上工作,最终到达选项卡栏控制器的子级,该子级将选项卡栏控制器作为其父级返回。

【讨论】:

  • 这是一个有趣的方法,但我很沮丧苹果似乎对修复它没有任何兴趣。我建议你提交错误。
  • 好吧,几个小时的痛苦之后,我决定搜索堆栈溢出,你在一分钟内为我解决了它。我希望我能给你所有的赞成票。
  • 疯了,这个问题在 iOS14 中仍然存在,很高兴我找到了这个答案,这让我发疯了
【解决方案2】:

原来这是一个 UIKit 错误,我已经提交了一个雷达 19996374。 解释如下:

当导航控制器放置在标签栏控制器内部时, 布局内容(您的)视图控制器的责任是 完全交给导航控制器。标签栏控制器 调整导航控制器视图的大小以匹配标签栏 控制器的视图范围。反过来,导航控制器帐户 布局内容视图控制器时的标签栏高度。 当您在选项卡栏之间注入视图控制器时,事情会中断 控制器和导航控制器。标签栏控制器看到 selectedViewController 不是 UINavigationController 并且 应用正常的布局规则。但包含导航控制器 看到它的 tabBarController 属性包含一个有效的 UITabBarController 实例并假设它仍然负责 用于在布局内容时处理标签栏高度(您的) 视图控制器。结果是内容视图控制器是 如您所见,两次插入标签栏高度

作为一种解决方法

您可以通过设置 isTranslucent 属性来解决此问题 选项卡栏的 YES。然后,在 AFbannerViewController 中,覆盖 -edgesForExtendedLayout 返回 UIRectEdgeAll。 AFbannerViewController 现在将覆盖标签栏(所以设置 背景颜色为粉红色以外的颜色),但导航 控制器会将正确的插图应用到内容视图控制器。

【讨论】:

  • 直到今天,这个 bug 仍然存在(测试 iOS 9、Xcode 7.3 和 Swift 2)。选项卡栏视图上的半透明 + 背景颜色 + edgesForExtendedLayout 到 .All 使一切再次正常工作。谢谢。
  • 不幸的是,即使我发送了一个显示该问题的小项目,我的错误仍会出现在“需要更多信息”中。
  • 此解决方案有效,但我不需要覆盖 edgesForExtendedLayout。
【解决方案3】:

确实遇到了完全相同的问题,并找到了您的帖子。

实际上,我设法用另一种方法修复它。

我的容器视图的顶部、前导和尾随约束都绑定到安全区域,但是,底部的设置为超级视图(见附件截图)

诀窍是使用 Extend Edges 配置,并将“Under Opaque bars”设置为 true,然后瞧。

我希望它可以帮助其他人。

问候

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    相关资源
    最近更新 更多