UINavigationController and UITableView frame issue - uitableview

self.tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
How do I get the proper size from the view, when I have a UINavigationController and a UITabBarController?
In order to get around it I have to do:
CGRect frame = self.view.frame;
frame.origin.y -= [UIApplication sharedApplication].statusBarFrame.size.height;
tableView = [[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain];
I always have to manually set the height of my views/tableviews in order to fit inside the UINavigationController and it's really annoying
This seems kinda strange, why would it not subtract the statusbar height auotmatically? It's the default style, not transparent statusbar.
Thanks
UPDATE: If I alloc the tableView AFTER the init method, just setting the frame to self.view.frame works fine. Wuzzup wit dat?

Setting the frame of the UINavigationController before the init method wouldn't work because the UINavigationController hasn't been loaded and displayed yet. The frame is only set after the controller and its view has been loaded.
You should be setting up your table (and all similar initializations) in the viewDidLoad method of the UINavigationController. If you do that you won't see any problems of this sort.

Related

How to make UITableview exact height and removing unwanted white space footer?

I have an following issue I am having one button on main view if i was click on this button add subview on the main view as tableview here is the code
ViewController *settings = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
settings.delegate=self;
[settings.view setFrame:CGRectMake(0, 30, self.view.frame.size.width,250)];
[self.view addSubview:settings.view];
after i was click on the button get the subview as tableview but rest of them having an whitespace.
then how to remove the remaining whitespace.
At first sight, it looks that you have set wrong height of your ViewController's view i.e., 250. Make sure the tableView inside the view have the same height as your are assigning in setFrame function here:
ViewController *settings = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
settings.delegate=self;
[settings.view setFrame:CGRectMake(0, 30, self.view.frame.size.width, HeightOfYourTableView)];
[self.view addSubview:settings.view];
Hope it helps!
You can simply calculate the height of your table view by multiplying the number of items by the height of the cell, let's say 44 by default.
But regarding the white background, you can do it from the Interface Builder or inside the code like this: (of course I am assuming that inside ViewController, you have access to the table view using some variable)
youTableView.backgroundColor = [UIColor clearColor];

Why does UIViewController extend under UINavigationBar, while UITableViewController doesn't?

I have UITabbarController with UINavigationController in it. I have a subclass of UIView that I assign as the view of UIViewController in the navController. This is pretty standard stuff, right? This is how I do it
_productCategoryView = [[ProductCategoryView alloc] initWithFrame:self.view.frame];
self.view = _productCategoryView;
This view has a UITableView as subView
_productCategoryTableView = [[UITableView alloc] initWithFrame:self.frame style:UITableViewStylePlain];
_productCategoryTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_productCategoryTableView.backgroundColor = [UIColor clearColor];
[self addSubview:_productCategoryTableView];
For the sake of debugging I am setting self.backgroundColor = [UIColor blueColor] on the view.
From the above initialization of tableView one might think that the view's and table's frame is same. However when I run in iOS 7, the view's origin is set behind the UINavigationBar. This is understandable because I am setting self.navigationBar.translucent = YES; in my subclass of UINavigationController. But what I don't understand is how come the table is sitting just below the navBar? Shouldn't it also start from (0, 0) which is behind the navBar? See screenshot Scenario 1 below. Notice the blue hue behind navBar
Now, I push another viewController on the navigation stack, simply by using [self.navigationController pushViewController.....]. Again I have a custom UIView with a tableView in it. However I also have a UILabel above this table, and again for debugging, I gave it a redColor. This time I am setting the label's origin to be almost same as the view's
CGRect boundsInset = UIEdgeInsetsInsetRect(self.bounds, UIEdgeInsetsMake(10, 10, 10, 10));
CGSize textSize = [_titleLabel.text sizeWithFont:_titleLabel.font
constrainedToSize:CGSizeMake(boundsInset.size.width, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
printSize(textSize);
_titleLabel.frame = CGRectMake(boundsInset.origin.x,
boundsInset.origin.y,
boundsInset.size.width,
textSize.height);
So, going by the logic above, the label should be visible, right? But this time it's not. This time the label is behind the navBar.
Notice, the red hue behind navBar.
I would really like to align the subView below the navBar consistently. My questions are
1. How is the tableView offset by 64pixels (height of nav + status bar in iOS 7) automatically, even though it's frame is same as the view's?
2. Why does that not happen in the second view?
By default, UITableViewController's views are automatically inset in iOS7 so that they don't start below the navigation bar/status bar. This is controller by the "Adjust scroll view insets" setting on the Attributes Inspector tab of the UITableViewController in Interface Builder, or by the setAutomaticallyAdjustsScrollViewInsets: method of UIViewController.
For a UIViewController's contents, if you don't want its view's contents to extend under the top/bottom bars, you can use the Extend Edges Under Top Bars/Under Bottom Bars settings in Interface Builder. This is accessible via the edgesForExtendedLayout property.
Objective-C:
- (void)viewDidLoad {
[super viewDidLoad];
self.edgesForExtendedLayout = UIRectEdgeNone;
}
Swift 2:
self.edgesForExtendedLayout = UIRectEdge.None
Swift 3+:
self.edgesForExtendedLayout = []
#Gank's answer is correct, but the best place to do this is on the UINavigationControllerDelegate (if you have one):
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
viewController.edgesForExtendedLayout = UIRectEdge.None
}

UIRefreshControl hidden / obscured by my UINavigationController's UINavigationBar

I'm attempting to use a UIRefreshControl inside my UITableViewController which itself is inside a UINavigationController, which has its hidesNavigationBar property set to NO (so the navigation bar is visible).
The UIRefreshControl works, but is obscured by the UINavigationBar. I'm surprised I can't find anyone else who has run into this problem.
Possible relevant points:
I set the rootViewController of my UIWindow to be my UINavigationController.
I set the initial view controller of the UINavigationController by setting the viewControllers property of the UINavigationController.
My UITableViewController subclass is instantiated with a nib.
I instantiate my UIRefreshControl in the viewDidLoad method of my UITableViewController subclass. I set the refreshControl property of the UITableViewController subclass in this method.
The UIRefreshControl works perfectly fine, and I can see a portion of it, but it is obscured by my UINavigationBar. It looks completely normal if I set hidesNavigationBar to YES (but I don't want to hide it).
Edit:
The code used to create and position my UIRefreshControl is:
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(toggleRefresh:)
forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
This code snippet is in the viewDidLoad method of my UITableViewController subclass, which is a child view controller of a UINavigationViewController.
For those targeting iOS 7, there seems to be a new issue present where the UIRefreshControl is drawn behind the UITableView's backgroundView. I experienced this both when initializing the UIRefreshControl programatically and from a storyboard. A simple workaround is to update the zPosition of the UIRefreshControl in viewDidLoad of your UITableViewController:
self.refreshControl.layer.zPosition = self.tableView.backgroundView.layer.zPosition + 1;
I've find a real solution, here it is:
I've a UIViewController inside a UINavigationController with a translucent NavigationBar. Inside the UIViewController there is the UITableView.
I want to add a UIRefreshControl but when I do it, it's hidden by the NavigationBar, like you explain.
Here is my code to make it work:
// Add a UITableViewController
self.tblViewController = [[UITableViewController alloc] init];
// Set the UITableView to it
self.tblViewController.tableView = self.tblView;
// Initialize the UIRefreshControl and set it's method
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(refreshTable) forControlEvents:UIControlEventValueChanged];
// Set the RefreshControl to the UITableViewController
self.tblViewController.refreshControl = self.refreshControl;
// Here is the thing ! Just change the contentInset to push down the UITableView content to 64 pixels (StatusBar + NavigationBar)
self.tblView.contentInset = UIEdgeInsetsMake(64.f, 0.f, 0.f, 0.f);
With this code, your UITableViewController will show the RefreshControl perfectly and keep the translucent NavigationBar effect when you scroll down the cells.
It looks like a bug to me, because it only occures when the contentOffset property of the tableView is 0
see this question
UIRefreshControl not showing spiny when calling beginRefreshing and contentOffset is 0
I fixed that with the following code (method for the UITableViewController) :
- (void)beginRefreshingTableView {
[self.refreshControl beginRefreshing];
if (self.tableView.contentOffset.y == 0) {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished){
}];
}
}
In iOS 7, self.view is under the navigationBar, except that you write something as follows,
self.edgesForExtendedLayout = UIRectEdgeNone; // or UIRectEdgeAll & ~UIRectEdgeTop
or
self.navigationViewController.navigationbar.translucent = NO;
Using #Jonathan's answer I got this working well. But since I am using storyboard I set the content inset there like so: Which in case someones needs:
(xcode 6.4)
Do not call -setTranslucent: on your UINavigationBar. Then, your refresh control will be positioned properly, below the navigation bar.

Replacing self.view with new UIView shows black view

I want to change the existing view in a UIViewController to a new view. The new view contains the old view and a little banner view.
Doing this fairly simple change leaves me with a black view.
My code looks like this
UIView *existingView = self.view;
UIView *newView = [[UIView alloc] initWithFrame:existingView.frame];
UIView *bannerView = [[UIView alloc] initWithFrame:CGRectMake(0, (self.view.frame.size.height - 50), 320, 50)];
CGRect existingViewFrame = existingView.frame;
existingViewFrame.size.height -= 50;
existingView.frame = existingViewFrame;
[newView addSubview:existingView];
[newView addSubview:bannerView];
self.view = newView;
However when switch Tabs and come back to the view which changed the view is shown just like I want. I guess I need to set a flag or something to tell the controller to redraw it's (new) view.
Edit
I wrote an simple example for this problem. You can find it on GitHub: https://github.com/Oemera/ChangeView
You did not say where you do this. It may be that you need to save the original view's super view, then add the new view to that views subViews array. I'm betting that is the problem.

Can't add UITableView as subview

Xcode 4.3/iOS 5.1/Storyboards.
I have a UIViewController with a UITableView in the storyboard
when initializing that view
-(void) loadView {
UITableView *tTableView = [[UITableView alloc] initWithFrame:CGRectMake(20,60, 300, 300)
style:UITableViewStyleGrouped];
[tTableView setDelegate:self];
[tTableView setDataSource:self];
[tTableView setBackgroundView:[[UIView alloc] initWithFrame:self.tableView.bounds]];
self.tableView = tTableView;
self.view = tTableView; // <--- THIS WORKS
}
This works, but the TableView is stretched over the entire width of the screen. I'd like it to be of a certain size as I'm using it for a login username/password control.
I was told to add it as a sub-view, but this crashes my app with some kind of recursive calling into the same "loadView" method.
-(void) loadView {
UITableView *tTableView = [[UITableView alloc] initWithFrame:CGRectMake(20,60, 300, 300)
style:UITableViewStyleGrouped];
[tTableView setDelegate:self];
[tTableView setDataSource:self];
[tTableView setBackgroundView:[[UIView alloc] initWithFrame:self.tableView.bounds]];
self.tableView = tTableView;
[self.view. addSubview: tTableView]; // <-- THIS CRASHES
}
Why is this crashing? How can I add the UITableView to a subview where I can control its width and not have it occupy the entire width of my screen?
you need to self.view = tTableView or self.view = [UIView alloc] initWithFrame.... and then add the table view. Overriding the loadView method means you are going to create the self.view. So for your case, create an UIView, set it to self.view and then add your tableView as subview of self.view
You use the loadView method, which means you define the view by yourself.
So self.view is not defined and the controller complains that its view is not defined when it should display itself.
Either put your interface in a xib (or storyboard) and bind those values in viewDidLoad, or instanciated the self.view by hand in loadView.

Resources