views:

189

answers:

1

In a Section Indexed UITableView how do you make the title of the section chosen (by pressing the Section Index) align *not* at the very top of the screen (under the navigation controller) but rather flush after the Navigation Bar Header at the top?

like this:


[button] Navigation Bar Header at top of screen [other button]
X (section letter)
items within section....

To be clear, the problem I am having is that when a section index is pressed on the right, the table scrolls that section to the very top of the screen, hidden underneath the navigation bar. I want that section header precisely after the navigation header touching the Navigation Bar bottom border with the top of the Section Letter row - as it is for example, when the table first appears.

+1  A: 

Better solution:

a) Get some sleep.

b) Realize that, while you were sleeping, the use of 'UIBarStyleBlackTranslucent' has been deprecated, so simply do this instead:

  • Open MainWindow.xib in Interface Builder, select your 'UINavigationBar' item inside the 'Navigation Controller' inside your 'Tab Bar Controller' and change the 'Style' to 'Black Opaque' instead of translucent.
  • In your UITableViewController class file, write

    - (void)viewWillDisappear:(BOOL)animated {
    self.navigationController.navigationBar.translucent = YES; /* Yes, go underneath the Navigation Bar elsewhere if you want to. */
    [super viewWillDisappear:animated];
    }
    - (void)viewWillAppear:(BOOL)animated {
    self.navigationController.navigationBar.translucent = NO; /* No going underneath the Navigation Bar. Problem solved! */
    ...
        [super viewWillAppear:animated];
    }
    

c) Stop feeling embarrassed and instead realize how sleep is now one more useful coding technique in your arsenal. ;p


The clues to the correct solution:

"The navigation controller never displays content under an opaque navigation bar."

"Set the translucent property of your navigation controller to YES. This allows your content to underlap the navigation bar."

see: developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/NavigationControllers/NavigationControllers.html

see: developer.apple.com/iphone/library/documentation/UIKit/Reference/UINavigationBar_Class/Reference/UINavigationBar.html#//apple_ref/occ/instp/UINavigationBar/translucent

UIBarStyle Defines the stylistic appearance of different types of views...

UIBarStyleBlackTranslucent = 2, // Deprecated

Use UIBarStyleBlack and set the translucent property to YES instead.

http://developer.apple.com/iphone/library/documentation/uikit/reference/UIKitDataTypesReference/Reference/reference.html


BEFORE SLEEPING, fixed it "The Hard Way"...

- (void)correctFrame:(UIView *)viewWithWrongFrame {
    CGRect correctedFrame = [[viewWithWrongFrame superview] frame];
    correctedFrame.size.height = correctedFrame.size.height - self.navigationController.navigationBar.frame.size.height; /* Height without Navigation Bar */
    correctedFrame.origin.y = correctedFrame.origin.y + self.navigationController.navigationBar.frame.size.height; /* Origin below Navigation Bar */
    [viewWithWrongFrame setFrame:correctedFrame];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    [self correctFrame:[self.navigationController.view.subviews objectAtIndex:0]]; /* Correct the frame so it is after the Navigation Bar */
    [self.tableView setContentInset:UIEdgeInsetsMake(-self.navigationController.navigationBar.frame.size.height, 0, 0, 0)]; /* Eliminate initial blank space at top.*/
    ...
}

- (void)cleanDisplay {
    [self.tableView setContentInset:UIEdgeInsetsZero]; /* Fix difference between horizontal and vertical orientation. */
    ...
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
    [self correctFrame:[self.navigationController.view.subviews objectAtIndex:0]]; /* Correct the frame so it is after the Navigation Bar */

    /* Clean the display after turning... */
    [self performSelectorOnMainThread:@selector(cleanDisplay) withObject:nil waitUntilDone:NO];
}
- (void)viewWillAppear:(BOOL)animated {
    ...
    [self performSelectorOnMainThread:@selector(cleanDisplay) withObject:nil waitUntilDone:NO];
    ...
}

Note that failed approaches included:

Using Interface Builder to embed the UITableView inside a UIView. Did not work because it all got automatically sized to the full height. Resizing [self.tableView superview].frame = CGRectInset([self.tableView superview].frame, 44, 44); or .bounds had no effect, neither did self.tableView.frame nor .bounds.

The clue to what was wrong came when I tried: self.navigationController.view.frame = CGRectInset(self.navigationController.view.frame, 20, 44); which actually changed the size of the view with the table in it. Clearly, changing the subview to that would fix the original problem.

Fixed it with the approach further above. Although before moving back or forward to other screens changes need to be reverted to normal to avoid shifting elements elsewhere.