I've got a UINavigationController with a UIViewController showing a navigation bar.
I've specifically set [self setAutomaticallyAdjustsScrollViewInsets:YES];, though this should be YES by default anyway.
I add a UIScrollView:
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.scrollView];
However, the UIScrollView's contentInset is {0, 0, 0, 0}, so I am wondering why it doesn't inherit the content inset from the view controller as the documentation states it would.
If I add subviews to the scroll view and set their Y to be self.scrollView.contentInset.top they don't appear below the navigation bar, which is what I am expected.
What am I doing wrong here? It works fine if you start out with a UITableViewController since it correctly inherits the contentInset from the view controller.
Thanks!
self.view = self.scrollView;
Works fine for me.
Tested with UIWebview:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view = self.webView;
}
It adjusts the scroll view bounds, not the content insets.
Related
Here I have created Navigation bar with height 50 and width as view size.Now, I want to add a subview in the navigation bar with same navigation bar size.How to set the frame size for subview?
ViewController.m
-(void)ViewDidLoad
{
UINavigationBar *navbar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
[self.view addSubview:navbar];
}
Firstly, your code won't respond to the orientation changes (portrait / landscape handling) nor support split screen. To fix it, instead of setting frame in viewDidLoad (where btw you do not call super!) write:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.navBar setFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
}
Then as it is a different view, you should create a subclass of your view. The code will work in a way as #raghu wrote, but it won't be easily maintanable and will be of low quality. Separate of concerns!
Inside your UIView subclass you should implement init methods and layoutSubviews where you should set a proper frame.
When I swipe and hide the navigation bar with the hidesBarsOnSwipe property the status bar has a clear background. How can I set the background of the status bar to the same color as the navigation bar? Here are a few pictures showing my problem, this is all contained in a UITableViewController.
Separate
Separate picture, looks like one big one.
I've come across the same issue, and was able to solve it. I'm fairly new to iOS dev, and I don't imagine this solution to be foolproof. I couldn't find any good answers elsewhere, so here's how I overcame it:
I converted from a UITableViewController over to UIViewController with a nested UITableView. Note, double check that the delegate to the child tableview is set to the UIViewController.
I Added a view with a height of 20px and a background colour that you want to set as the "background" to the status bar. Set the constraints on that view as follows:
On your table view, set the constrains to be basically full screen. One important note here, the top constraint is to "Top Layout Guide.Top" and not to "Top Layout Guide.Bottom". By default I believe this constraint ties to the bottom. Double clicking on the constraint allows you to adjust it to the top. Without this, any table header cells weren't positioned properly for me
Hope that helps.
Adding to George Huber's answer. I solved this issue programmatically by adding a 20pt height UIView as a subview of the navigationController's view property -- in viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *statusBarBG = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 20)];
statusBarBG.backgroundColor = [UIColor navBar];
[self.navigationController.view addSubview:statusBarBG];
// REST OF CODE
}
Per skg's answer, I add a relative height for status bar according to iOS version.
self.navigationController.hidesBarsOnSwipe = true;
// add a UIView as subView to navigationController
CGFloat statusBarHeight;
if (#available(iOS 13, *)) {
NSArray *windows = UIApplication.sharedApplication.windows;
UIWindow *keyWindow = nil;
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
keyWindow = window;
break;
}
}
statusBarHeight = keyWindow.windowScene.statusBarManager.statusBarFrame.size.height;
NSLog(#"statusBarHeight: %f", statusBarHeight);
} else {
statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
}
UIView *statusBarBG = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), statusBarHeight)];
statusBarBG.backgroundColor = [UIColor systemBackgroundColor];
[self.navigationController.view addSubview:statusBarBG];
How would you change the height of the main view so that its height does not go beyond the tabbed navigation bar? I want the main view to be above the tabbed navigation bar.
I believe you want the content to not show up behind the navigation bar. If this is correct you can uncheck the Under Top Bars in your view controller.
You can try this with code
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
you may also need to add
self.navigationController.navigationBar.translucent = NO;
The self.navigationController.navigationBar.translucent = NO; should be all you need, however depending on your setup and what you are doing with the navigation bar you may need the additional code above.
You can add those into your viewDidLoad or into viewDidLayoutSubviews
If that doesn't work you can try something like this if you need to support ios 6 as well.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.view.frame = CGRectMake(0,
self.topOfViewOffset,
self.view.frame.size.width,
self.view.frame.size.height);
}
So if you have a content view that has a width as wide as your ViewController, that has an origin point of 0,0 (it's top left corner starts at the very top left hand corner of the view) and that has a navigation controller directly below it, I would do something like this in my ViewDidLoad method:
yourcontentview.frame = CGRectMake(0, //x co-ordinate
0, //y co-ordinate
self.view.frame.width, //set width as wide as the view's
self.view.frame.height - yournavigationbar.frame.height); //take the height of the nav controller away from the view and see what space is left.
or alternatively if your nav controller is NOT at the very bottom of your view change:
self.view.frame.height - yournavigationbar.frame.heigh
to
self.view.frame.heigh - yournavigationbar.frame.origin.y
The above ^ gets the start location of the nav controller in the view (so if it starts at 500 points down, then the height of the contentview will not go past 500 points)
Hope they work!
also if there is lots of content, you can always stick it in a scrollview :)
I have a custom UIViewController which create a view containing an action bar at the top (view with 4 buttons), a tableview and then another view below the tableview. Layout is done all in code and is not using auto layout.
Everything works perfectly on various device with iOS 7.0 and 7.0.2, but in the simulator, the root view of the controller get anchored at the top right corner of the screen (0,0) instead of below the navigation bar.
I'm going to force the relay out in the viewDidAppear: method, but this seem like a hack...
Thanks for any insights
Edit: added an image. You can see the UIView highlighted. As ManicMonkOnMac mentioned, the UIView is under the toolbar (but this only happens in the simulator, on the device, the view lines up fine)
In the loadView method on the controller, i set the frame when creating the view:
- (void)loadView
{
// Our parent view controller will resize us appropriately. The size set
// here is a convenience for initial view layout.
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
But this frame is later changed. Not by my code, though, but by UIkit code)
Edit2: addded loadView method body
EDIT: After going through session 201 of WWDC 2013, I think I have the solution.
in iOS 7 there is a property that you can set on your view controllers to specify whether you want the views to be overlapped by navigation bar.
viewController.edgesForExtendedLayout = UIRectEdgeNone;//UIRectEdgeAll specifies that nav bars should overlap the view.
Unlike iOS 6, navigation bars are placed over the views in iOS 7.
Use the frame size that excludes the navigation bar.
code:
CGRect frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y+self.navigationController.navigationBar.frame.size.height,self.view.frame.size.width,self.view.frame.size.height);
CustomView *view = [[CustomView alloc] initWithFrame:frame];
[self.view addSubview: view];
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
}