Why the 20px gap at the top of my UIViewController? Why the 20px gap at the top of my UIViewController? ios ios

Why the 20px gap at the top of my UIViewController?


The behaviour you are seeing is not a bug at all but merely a side effect of your misuse of adding views into a hierarchy.

When you add the tableView into a view you need to tell UIKit how you want that tableView to size relative to its parent. You have two options: Auto-Layout or Autoresizing Masks. Without describing how you want your view to layout UIKit simply pops it onto the hierarchy and the default implementation will lay your view under the top layout guide (which just happens to be the height of the status bar). Something as simple as this would do the trick:

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

This behavior is not actually exclusive to UITableViewController but also to UICollectionViewController. I believe their default viewLoading implementation insets the view under the status bar. If we make our childController a simple UIViewController subclass none of this behaviour is exhibited. Don't see this as a bug though, if you explicitly declare how you want their respective views to be laid out you won't have this issue. Naturally, this is the primary function of a container controller.

Heres what your appDelegate should look like:

Xamarin

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}

Note I wrote a post recently describing the ways you can configure a view to fill its superview


Your problem seems to relate to some kind of fundamental issues with UITableViewController being directly added as a child controller of another.

Looking around this is not a new issue: iOS 7: UITableView shows under status bar

Relative to that article, I took your code and tried the following options (once I realized it was in C# 8^)):

  1. Instead of using a UITableViewController, add a UIViewControllerand then add a UITableView as a child of the UIViewController.If you do this then there is no 20pt issue. This highlights that theproblem is with the UITableViewController class.

    This approach is a relatively clean workaround and only a couple ofextra steps on what you have already.

    I did try adding constraints in your original code to force theUITableViewController frame to the top, but could not get this towork. Again this could be down to the table controller overridingthings itself.

  2. If you build your demo using storyboards, everything works. This Ibelieve is down to the fact that IB itself uses a container view toembed the new view controller. So if you use storyboard, the wayapple does it is to add a view which you can set the frame of usingconstraints and it then embeds the UITableViewController insidethat view via an embed Segue.

    Hence as per 1), using a view in the middle seems to solve the issueand again it seems that having control over the middle views frameis key.

    I notice in your only viable workaround, that changing the frame wasthe answer. However post iOS7, changing the frame does not seem tobe recommended due to the issues it can have clashing withconstraints which also want to manipulate the frame.

  3. Trying other options like edgesForExtendedLayout all seemed tofail. These seem to be hints for container view controllers andUITableViewController is ignoring them.

IMHO I think option 1) seems the safest approach as you have total control over the layout and are not fighting the system with frame overrides which may cause you issues later. Option 2) only really works if you use storyboards. You could try doing the same thing manually yourself, but who knows what goes on in an embed Segue.

EDIT

It would seem that there was a missing step as highlighted by Arkadiusz Holko in his answer and setting the frame explicitly for the table view does fix the issue.


You missed one step when adding a child view controller – setting up its view's frame.

See the second step:

- (void) displayContentController: (UIViewController*) content;{  [self addChildViewController:content];                 // 1  content.view.frame = [self frameForContentController]; // 2  [self.view addSubview:self.currentClientView];  [content didMoveToParentViewController:self];          // 3}

Source: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html