1

I have a view controller that sets up a UIImageView and a UITableView as follows in viewDidLoad:

// Root UIView
UIView *rootView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
rootView.backgroundColor = [UIColor redColor];
self.view = rootView;

// Image View
NSString *path = [[NSBundle mainBundle] pathForResource:@"test320x180" ofType:@"JPG"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
self.imageView.image = image;
[self.view addSubview:self.imageView];

// Table View
self.tableView = [[UITableView alloc] initWithFrame:rootView.frame style:UITableViewStylePlain];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.contentInset = UIEdgeInsetsMake(image.size.height, 0, 0, 0);
self.tableView.contentOffset = CGPointMake(0, -image.size.height);
self.tableView.backgroundColor = [UIColor clearColor]; // so we can see the image view
[self.tableView reloadData];
[self.view addSubview:self.tableView];

There are 20 pts between the bottom of the image view, which has CGRect: (0, 0, 320, 180), and the first cell of the Table View whose origin is (0, 200), shown in red in the screen shot below.

resultingView

In reveal, I see that the TableView starts 20 pts below the ImageView, screenshot below. My best guess is that the table view automatically accounts for the status bar but the image view does not.

revealScreeny

My intention is to have the image and the first tableview cell flush, but I'm not sure how to guarantee this without adding the magic number 20 to my code.

JuJoDi
  • 14,627
  • 23
  • 80
  • 126
  • What is the tool you're using to show/"reveal" the xib in that manner (with the red background) and the 3d view (much like one of firefoxes webdev tools)? – Stu P. Jan 07 '14 at 21:28
  • It's actually called [Reveal](http://revealapp.com/). – JuJoDi Jan 10 '14 at 19:01

3 Answers3

4

[[UIScreen mainScreen] applicationFrame] returns a value that includes the entire height of the screen, including the height of the status bar, and always in screen coordinates.

For example on a 3.5-inch iPhone, in both portrait and landscape, you'll get the same application frame:

{ 0,0, 320, 480 } // iPhone 3.5-inch, applicationFrame in both landscape and portrait

When you assign a frame with 0 for origin.y to the image view, then add it via:

[self.view addSubview:self.imageView];

... then the self.imageView's top 20 pixels are hidden beneath the status bar.

Please note, sometimes the status bar's height is doubled, such as by a phone call, or recording audio within an app, or Personal Hotspot/tethering. To survive that, you need the value from:

CGSize size = [[UIApplication sharedApplication] statusBarFrame].size;

This is returned in Screen coordinates, so the returned rect may be:

{ 0,0, 320, 20 } // iPhone 3.5-inch, portrait
{ 0,0, 20, 480 } // iPhone 3.5-inch, landscape
{ 0,0, 320, 40 } // iPhone 3.5-inch, portrait when tethering or other phone call
{ 0,0, 40, 480 } // iPhone

So the quick solution is to use something like the above CGRect size code with the following:

CGFloat height = (size.width < size.height? size.width : size.height);

3.5-inch, landscape when tethering or other phone call

  1. Set the size of the frame of rootView using a CGRect that is adjusted for the status bar height, so the imageView.frame.origin.y == 0 is not hidden by the status bar
  2. Set imageView's frame origin y to the status bar height (which means the rootView's content is still overlapped by the status bar).
Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
Tom Pace
  • 2,347
  • 1
  • 24
  • 32
  • 1
    Thanks. After I init'd the rootView I did `rootView.frame = CGRectOffset(rootView.frame, 0, -[[UIApplication sharedApplication] statusBarFrame].size.height);` which seems to have fixed it. – JuJoDi Dec 07 '13 at 03:08
  • As an add, you can disable the iOS 7 extended edge insets via `self.edgesForExtendedLayout = UIRectEdgeNone;` or deselect "Extend Edges..." on the desired ViewController in storyboard. There is a lengthy discussion on this http://stackoverflow.com/questions/18900428/ios-7-uitableview-shows-under-status-bar – Chris Dec 07 '13 at 03:14
  • 1
    @JuJoDi Cool. I also recommend adding self as an observer to NSNotificationCenter for UIApplicationWillChangeStatusBarFrameNotification and UIApplicationDidChangeStatusBarFrameNotification. Check out https://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/constant_group/UserInfo_Dictionary_Keys – Tom Pace Dec 07 '13 at 03:15
  • Thanks, that will probably go into the final version for sure. – JuJoDi Dec 07 '13 at 03:24
0

UITableView is a subclass of UIScrollView so check the contentInset property and also set the UIViewController property automaticallyAdjustsScrollViewInsets is set to NO.

I think automaticallyAdjustsScrollViewInsets applies insets to all scroll views to account for status bars, button bars and navigation bars.

Joseph Lord
  • 6,446
  • 1
  • 28
  • 32
0

I faced this same issue, while i was working in storyboard where my tableview was having same 20 pixel gap. so what you need to do is:

1.) select your view controller and in attribute inspector deselect "Adjust scroll view inset". (this will remove the gap - that tableview is presuming for navigation bar)

2.) select your tableView and in size inspector set the "section header height" == '1' (this will remove the 20 pixel gap - that tableview is presuming for status bar)

Hope will help you! Thanks

rahulchona
  • 592
  • 4
  • 10