ios - 为什么我的 UIViewController 顶部有 20px 的间隙?

标签 ios layout uiviewcontroller xamarin

问题

考虑以下 Controller 层次结构:

  • UINavigationController
    • UIViewController
      • UITableViewController

UIViewController 的存在会影响布局。没有它,UITableViewController 会占据 UINavigationController 的整个边界:

enter image description here

但是,如果我在 UINavigationControllerUITableViewController 之间添加一个 Vanilla UIViewController 顶部之间会出现 20px 的间隙UIViewControllerUITableViewController 的顶部:

enter image description here

即使我将我的代码减少到最简单的可能,我仍然观察到这种行为。考虑这个应用委托(delegate)代码:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    window = new UIWindow(UIScreen.MainScreen.Bounds);

    var tableView = new UITableViewController();
    var intermediateView = new UIViewController();
    var navigation = new UINavigationController(intermediateView);

    navigation.View.BackgroundColor = UIColor.Red;
    intermediateView.View.BackgroundColor = UIColor.Green;
    tableView.View.BackgroundColor = UIColor.Blue;

    intermediateView.AddChildViewController(tableView);
    intermediateView.View.AddSubview(tableView.View);
    tableView.DidMoveToParentViewController(intermediateView);

    window.RootViewController  = navigation;
    window.MakeKeyAndVisible();

    return true;
}

上面的仍然显示了 UIView 顶部和 UITableView 顶部之间有 20px 的间隙。

我对问题的理解

我知道某事错误地为状态栏分配了空间。使用 Reveal,我可以看到 UITableViewControllerFrameY 值为 20

我尝试过的事情

不成功

  • UIViewControllerUITableViewController 和两者上将 WantsFullScreenLayout 设置为 true
  • UIViewControllerUITableViewController 使用 EdgesForExtendedLayoutExtendedLayoutIncludesOpaqueBars
  • UIViewController 上玩过 AutomaticallyAdjustsScrollViewInsets
  • UITableView 中使用 PreservesSuperviewLayoutMargins
  • 尝试覆盖 PrefersStatusBarHidden 并在 UIViewControllerUITableViewController 中返回 true

成功

因此在我的 UITableViewController 中覆盖 ViewDidLayoutSubviews:

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();
    this.View.Frame = this.View.Superview.Bounds;
}

我想知道的事

  • 是否有一种干净(呃)的方式来实现我的目标?
  • 增加 20px 间隙的真正原因是什么? UIViewControllerUITableViewController?
  • 确保我的 View Controller 在不同上下文中保持可用的最佳做法是什么?大概覆盖 ViewDidLayoutSubviews 将我的 View Controller 与关于它将在可视化树中显示的位置的期望相结合。如果它被托管在 Controller 堆栈的更高位置,事情看起来就不对了。有没有办法避免这种耦合,从而提高可重用性?

最佳答案

您看到的行为根本不是错误,而仅仅是您滥用将 View 添加到层​​次结构的副作用。

当您将 tableView 添加到 View 中时,您需要告诉 UIKit 您希望 tableView 相对于其父 View 的大小如何。您有两个选择:Auto-Layout或自动调整蒙版。无需描述您希望 View 如何布局,UIKit 只是将其弹出到层次结构中,默认实现会将您的 View 置于顶部布局指南下方(恰好是状态栏的高度)。像这样简单的事情就可以解决问题:

tableVC.View.Frame = rootVC.View.Bounds
tableVC.View.Autoresizingmask = UIViewAutoresizing.FlexibleWidth
tableVC.View.TranslatesAutoresizingMaskIntoConstraints = true// always nice to explicitly use auto layout

此行为实际上并非 UITableViewController 独有,UICollectionViewController 也独有。我相信他们的默认 viewLoading 实现会在状态栏下插入 View 。如果我们使我们的 childController 成为一个简单的 UIViewController 子类,则不会出现任何这种行为。不要将此视为错误,如果您明确声明您希望如何布置它们各自的 View ,则不会出现此问题。自然,这是容器 Controller 的主要功能。

你的 appDelegate 应该是这样的:

赛马林

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    window = new UIWindow(UIScreen.MainScreen.Bounds);

    var tableVC = new UITableViewController();
    var rootVC = new UIViewController();
    var navigationVC = new UINavigationController(intermediateView);

    navigationVC.View.BackgroundColor = UIColor.Red;
    rootVC.View.BackgroundColor = UIColor.Green;
    tableVC.View.BackgroundColor = UIColor.Blue;

    rootVC.AddChildViewController(tableVC);
    rootVC.View.AddSubview(tableVC.View);


    //YOU NEED TO CONFIGURE THE VIEWS FRAME
    //If you comment this out you will see the green view under the status bar
    tableVC.View.Frame = rootVC.View.Bounds
    tableVC.View.Autoresizingmask = UIViewAutoresizing.FlexibleWidth
    tableVC.View.TranslatesAutoresizingMaskIntoConstraints = true
    tableVC.DidMoveToParentViewController(rootVC);

    window.RootViewController  = navigationVC;
    window.MakeKeyAndVisible();

    return true;
}

swift

var window: UIWindow?
var navigationControlller: UINavigationController!

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    let rootVC = UIViewController(nibName: nil, bundle: nil)
    let tableVC = UITableViewController(style: .Plain)
    let navVC = UINavigationController(rootViewController: rootVC)
    navVC.navigationBarHidden = true

    navVC.view.backgroundColor = UIColor.redColor()
    rootVC.view.backgroundColor = UIColor.greenColor()

    rootVC.view.addSubview(tableVC.view)

    //YOU NEED TO CONFIGURE THE VIEWS FRAME
    //If you comment this out you will see the green view under the status bar
    tableVC.view.frame = rootVC.view.bounds
    tableVC.view.autoresizingMask = .FlexibleWidth | .FlexibleHeight
    tableVC.view.setTranslatesAutoresizingMaskIntoConstraints(true)

    rootVC.addChildViewController(tableVC)
    tableVC.didMoveToParentViewController(rootVC)

    window = UIWindow(frame: UIScreen.mainScreen().bounds)
    window?.rootViewController = navVC
    window?.makeKeyAndVisible()

    return true
}

注意 我写了一个post recently描述配置 View 以填充其父 View 的方式

关于ios - 为什么我的 UIViewController 顶部有 20px 的间隙?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30525403/

相关文章:

iphone - 防止在 iOS 中备份文件

ios - 弹出窗口关闭时禁用 UIBarButtonItem

java - 使用默认布局将 JPanel 添加到 JFrame

android - 覆盖android :id attribute with <include> doesn't work

ios - 在 Swift 中,如何在不同的 ViewController 中永久更改 a 的标签文本?

ios - 具有不同行为的 BarButton 项目

ios - UITableView 内的 CollectionView Cell 不会水平滚动以获得 Voice Over 可访问性

c# - 动态 Windows 窗体组件(性能问题)

iphone - 自定义 UIView 子类作为 UIViewController 属性

ios - 为什么 iOS 在 didReceiveMemoryWarning 释放后不自动旋转从 Nib 加载的 View ?