5

I am trying to add a UITableView object that covers up the whole screen, by

  UITableView *tabelView = [[UITableView alloc] initWithFrame:self.view.bounds];
  [self.view addSubview:tabelView];

but I realized that even if a physical iPad 2 is rotated to Landscape mode, self.view.bounds is {{0, 0}, {768, 1004}} in viewDidLoad and viewWillAppear. Only in viewDidAppear is it finally {{0, 0}, {1024, 748}}

What is the earliest time that self.view.bounds is set correctly to {{0, 0}, {1024, 748}}? If viewDidAppear is the one, then I have to create the UITableView there, and if the "Launch image" is a static Landscape blank table, then the screen will flash a white screen when viewDidAppear is called, and then the table is added and seen, so a flash of white screen is seen.

So when is the earliest time that self.view.bounds is set correctly to {{0, 0}, {1024, 748}}? It seems like it needs to be slightly before viewDidAppear, so that the blank table is drawn (with the grey lines), and show it and seamlessly get displayed to cover up the Launch image. If the table is created in viewDidLoad or viewWillAppear using self.view.bounds, then the table ends up being 768 points wide and is meant for the Portrait mode.

Update: I just tried to add the Launch image and for some reason, even if the UITableView is added in viewDidAppear, the "flash of white screen" didn't happen... I don't know why, but previously if I use CALayer and bitmap to show content, and didn't use any view or drawRect, then the flash occurred... by the way, the earliest one I found was viewWillLayoutSubviews, and then later in viewDidLayoutSubviews, both of which happened before viewDidAppear, and both showed self.view.bounds as {{0, 0}, {1024, 748}}

Update 2: What if the view is complicated and time consuming to make? To test, I added a usleep(100000); in the tableView:cellForRowAtIndexPath to sleep 0.1 second for each cell, and the "flash" did occur... but cell and table supposedly should be light weight and fast to make, but what if there are other type of views that are more time consuming to make? If I move UITableView creation to viewWillLayoutSubviews, then it is still slow to show something, but at least there is no "flash". However, later on when I rotate the device, it actually call viewWillLayoutSubviews again and add another table to the main view (with correct screen size), so viewWillLayoutSubviews will need to remove any old table view first, if any, or just resize the old one and not add a new one.

nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • Whilst the self.view.bounds updates later on, if you grab the interface orientation using [UIApplication sharedApplication].statusBarOrientation you can decide how to size your table before waiting for the bounds to be set. – Luke Aug 25 '12 at 03:30
  • @Luke if this work, this may be a little bit of a hack because what if a future device of iOS comes out, and it is not the iPhone or iPad resolution and we need to count on `self.view.bounds`? – nonopolarity Aug 25 '12 at 03:32
  • Apple tend to be kind with these things, but whilst I understand what you're saying, you could do it this way anyway (as you want to draw the table before the view appears) and then compare the frame you generated with the final self.view.bounds and then adjust if necessary. – Luke Aug 25 '12 at 03:35
  • @Luke please see update in the question – nonopolarity Aug 25 '12 at 03:58
  • possible duplicate of [UIViewController returns invalid frame?](http://stackoverflow.com/questions/9539676/uiviewcontroller-returns-invalid-frame) – rob mayoff Aug 25 '12 at 07:38

2 Answers2

4

The simplest way to avoid the flash is to create the table view in viewDidLoad and set the table view's autoresizing mask properly, so that the system automatically makes the table view fill its superview:

- (void)viewDidLoad {
    [super viewDidLoad];
    UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
    tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:tableView];
}

Otherwise, the earliest time that you can see the final view bounds are in the view controller's viewWillLayoutSubviews method. You would add your table view once in viewDidLoad, and then adjust its frame in viewWillLayoutSubviews or a method called after that. See my answer to UIViewController returns invalid frame? for more details.

Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • actually, it does work -- there is no flash even if I add a `sleep(1)` in the cell data source provider, so even though the table is very slow to come out (say, 5 or 10 seconds), there is no flash, and it is an interesting concept: we first set the view to an "incorrect" size first, and let the "resize" handle it before showing it on screen – nonopolarity Aug 25 '12 at 20:34
  • is there a `viewWillResizeSubviews` also? I googled and searched in the link in your answer and don't see a resize message like that? – nonopolarity Aug 25 '12 at 20:35
  • There is no `viewWillResizeSubviews` message. A view only resizes its subviews when it performs autolayout, and you receive `viewWillLayoutSubviews` immediately after that. – rob mayoff Aug 25 '12 at 21:12
  • because you mentioned `viewWillResizeSubviews` in your answer... where does it belong to? – nonopolarity Aug 27 '12 at 20:03
1

I was trying to solve a similar problem - I wanted to load some UI elements programmatically based on the size of a UIView added in Interface Builder.

Inside viewDidLoad and viewWillAppear, the UIView still hadn't had its frame/bounds set. Placing my code inside viewDidAppear worked, however it meant that the UI would "flash" with an update rather than appearing already loaded when the UIViewController was pushed onto the navigation stack.

I found that overriding viewDidLayoutSubviews solved the problem - at that point, the view had its bounds and frame set - I could add in my own subviews relative to its size, all before viewDidAppear.

The end result is that the UI loaded properly before it appeared, and hence didn't "flash" in for the user.

Chris McGrath
  • 1,936
  • 16
  • 17