4

My Problem

I am using a UITabBarController inside a UINavigationController. And there are three tableviews inside the UITabBarController. As shown in the picture, the first table view shows correctly while the other two tableviews are partially hidden behind the navigation bar. How can I fix this?

enter image description here enter image description here enter image description here

My hierarchy:

  • Root: UINavigationController
    • UITabBarController
      • UITableViewController (table1,table2,table3)

Here is my code:

AppDelegate.m

#import "AppDelegate.h"
#import "TableViewController.h"
@interface AppDelegate()
@property UINavigationController* nav;
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    TableViewController* table1 = [[TableViewController alloc]init];
    TableViewController* table2 = [[TableViewController alloc]init];
    TableViewController* table3 = [[TableViewController alloc]init];
    table1.title = @"table1";
    table2.title = @"table2";
    table3.title = @"table3";
    UITabBarController* t = [[UITabBarController alloc] init];
    [t setViewControllers:@[table1,table2,table3]];
    self.nav = [[UINavigationController alloc] initWithRootViewController:t];
    [self.window setRootViewController:self.nav];
    [self.window makeKeyAndVisible];
    return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application{}
- (void)applicationDidEnterBackground:(UIApplication *)application{}
- (void)applicationWillEnterForeground:(UIApplication *)application{}
- (void)applicationDidBecomeActive:(UIApplication *)application{}
- (void)applicationWillTerminate:(UIApplication *)application{}
@end

TableViewController.m

#import "TableViewController.h"
@implementation TableViewController
- (id)initWithStyle:(UITableViewStyle)style{
    self = [super initWithStyle:style];
    if (self) {}
    return self;
}
- (void)viewDidLoad{
    [super viewDidLoad];
    [self.tabBarController.view layoutSubviews];
}
- (void)didReceiveMemoryWarning{
    [super didReceiveMemoryWarning];
}
#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell* c = [[UITableViewCell alloc] init];
    [c.textLabel setText:[NSString stringWithFormat:@"%d", indexPath.row]];
    return c;
}
@end
user94602
  • 883
  • 1
  • 7
  • 8
  • did you try to set self.tableView.contentInset = UIEdgeInsetsMake(64.0f, 0.0, 0.0, 0.0);? inside your UITableviewControllers – iiFreeman Dec 26 '13 at 13:55
  • Check this answer: http://stackoverflow.com/questions/17074365/status-bar-and-navigation-bar-appear-over-my-views-bounds-in-ios-7/18785646#18785646 – LE SANG Dec 26 '13 at 13:56
  • self.tableView.contentInset = UIEdgeInsetsMake(64.0f, 0.0, 0.0, 0.0); will make table2 ad table3 look ok but also make table1 lowered by 64 points. – user94602 Dec 26 '13 at 14:22
  • @১২৩: thank you it works. btw what language is your name in? – user94602 Dec 26 '13 at 14:46
  • i am late but ... anyone who got the same problem should uncheck automatically adjust scroll view insets .....from attributes inspector will do the trick – Abu Ul Hassan Sep 28 '17 at 09:53

2 Answers2

5

Typically, the hierarchy is

UITabBarController
    - UINavigationController
        - UITableViewController

Why are you trying to put the Navigation Controller on top? Try reorganizing using a tab bar full of navigation controllers instead.

coneybeare
  • 33,113
  • 21
  • 131
  • 183
  • I am trying to do this because I want that when a row in table1 is selected, it will push a new view controller in full screen while keeping the navigation bar. I do not want the tab bar in the new pushed new view. I also do know want to simple set the tab bar to disappear, because that would be not smooth. – user94602 Dec 26 '13 at 14:13
  • The Tab bar controller is not designed to be anywhere but on top of the view hierarchy. So even if you find a hack to get past this issue (as it may not be related to the controller hierarchy), you will surely come across others as your development progresses. I would play with the hiding of the tab bar as your focus. – coneybeare Dec 26 '13 at 14:27
  • As much as I hate to say it, the docs for UITabBarController say that a UITabBarController MUST be at the root of the hierarchy. "When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller." – Kenny Wyland Mar 12 '14 at 03:16
  • 1
    @user94602 now you can use this for show new view controller full screen: `newViewController.hidesBottomBarWhenPushed = YES;`, this work fine with hierarchy that coneybeare cited. – iTSangar Nov 12 '14 at 15:36
1

I hit this same problem yesterday, and decided to work around it. It's just one class that gets in the way, so here's the rewrite:

DRTabBarController.h

//
// Created by Dan Rosenstark on 2/28/15.
// Copyright (c) 2015 Confusion Studios LLC. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface DRTabBarController : UIViewController <UITabBarDelegate>;

@property (nonatomic, strong) NSArray *viewControllers;
@property (nonatomic, strong) UITabBar *tabBar;
@property (nonatomic, strong) UIView *mainView;

@end

DRTabBarController.m

//
// Created by dr2050 on 2/28/15.
// Copyright (c) 2015 Confusion Studios LLC. All rights reserved.
//

#import "DRTabBarController.h"


@implementation DRTabBarController {


}


- (instancetype)init {
    self = [super init];
    if (self) {
        self.tabBar = [[UITabBar alloc] init];
        self.tabBar.delegate = self;
        self.tabBar.tintColor = [UIColor whiteColor];
        self.tabBar.barStyle = UIBarStyleBlack;
        self.tabBar.backgroundColor = [UIColor blackColor];

        self.mainView = [[UIView alloc] init];
    }
    return self;
}

- (void)viewDidLoad {
    [self.view addSubview:self.tabBar];
    [self.view addSubview:self.mainView];
}

- (void)setViewControllers:(NSArray *)viewControllers {
    _viewControllers = viewControllers;

    NSMutableArray *tabBarItems = [NSMutableArray array];
    for (UIViewController *controller in viewControllers) {
        UITabBarItem *item = controller.tabBarItem;
        [tabBarItems addObject:item];
    }
    self.tabBar.items = tabBarItems;
}


- (void)viewWillAppear:(BOOL)animated {
    [self.tabBar setSelectedItem:self.tabBar.items.firstObject];
    [self tabBar:self.tabBar didSelectItem:self.tabBar.items.firstObject];
}

- (void)viewDidAppear:(BOOL)animated {



}

-(void)viewDidLayoutSubviews {
    CGRect frame = self.view.bounds;
    UITabBarController *throwaway = [[UITabBarController alloc] init];
    frame.size.height = throwaway.tabBar.frame.size.height;
    frame.origin.y = self.view.bounds.size.height - frame.size.height;
    self.tabBar.frame = frame;
    self.tabBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;

    frame = self.view.bounds;
    frame.size.height -= self.tabBar.frame.size.height;

    float navbarHeight = self.navigationController.navigationBar.frame.size.height;
    // cannot use UIApplication.sharedApplication.statusBarFrame.size.height because
    // reports are not right with in-call status bar
    float statusBarHeight = UIApplication.sharedApplication.statusBarHidden ? 0 : 20;
    float topBarHeight = navbarHeight + statusBarHeight;

    frame.origin.y += topBarHeight;
    frame.size.height -= topBarHeight;
    self.mainView.frame = frame;
    self.mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
}

- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
    int index = [self.tabBar.items indexOfObject:item];
    NSArray *subviews = self.mainView.subviews;
    for (UIView *view in subviews) {
        [view removeFromSuperview];
    }
    UIView *view = [[self.viewControllers objectAtIndex:index] view];
    view.frame = self.mainView.bounds;
    view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.mainView addSubview:view];
}


@end

Note: There's one magic variable in there -- 20 -- for the in-call status bar, which has a totally different relationship to the surrounding nav...

Any help with this would be appreciated, but does work.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421