iOS hidesBarsOnSwipe status bar background color - ios

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];

Related

Centering a custom navigation bar item using layout anchors

I have created a custom navigation item (with both title and a UISearchBar) to replace the standard navigation title on iOS and I am trying to center it in a UINavigationBar using layout anchors.
However, the layout constraint [self.navigationItem.titleView.centerXAnchor constraintEqualToAnchor:self.navigationController.navigationBar.centerXAnchor].active = YES; does not work and the UIView containing the search bar shows up on the left side of the UINavigationBar.
Other constraints:
The width should be 1/3 of the screen width
I want to avoid setting width as a constant to make the view responsive in response to orientation and other layout changes
How to center the navigation bar item?
ScreenViewController.m:
- (void) viewDidLoad {
[super viewDidLoad];
// Create the search bar
self.searchBar = [SearchBar new];
// Create a new UIView as titleView (otherwise I'm receiving an error)
self.navigationItem.titleView = [UIView new];
// Add into view hierarchy and turn off auto constraints
[self.navigationController.navigationBar addSubview:self.navigationItem.titleView];
[self.navigationItem.titleView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.navigationItem.titleView addSubview:self.searchBar.view];
[self.searchBar.view setTranslatesAutoresizingMaskIntoConstraints:NO];
// Set anchors for the wrapping view
[self.navigationItem.titleView.widthAnchor constraintEqualToAnchor:self.navigationController.navigationBar.widthAnchor multiplier:1.0/3.0].active = YES;
//[self.navigationItem.titleView.heightAnchor constraintEqualToConstant:50.0].active = YES;
[self.navigationItem.titleView.topAnchor constraintEqualToAnchor:self.navigationController.navigationBar.topAnchor].active = YES;
[self.navigationItem.titleView.centerXAnchor constraintEqualToAnchor:self.navigationController.navigationBar.centerXAnchor].active = YES;
[self.navigationItem.titleView.bottomAnchor constraintEqualToAnchor:self.navigationController.navigationBar.bottomAnchor].active = YES;
// Set anchors for the search bar
[self.searchBar.view.widthAnchor constraintEqualToAnchor:self.navigationItem.titleView.widthAnchor multiplier:1.0].active = YES;
//[self.navigationItem.titleView.heightAnchor constraintEqualToConstant:50.0].active = YES;
[self.searchBar.view.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor].active = YES;
[self.searchBar.view.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor].active = YES;
//[self.searchBar.view.leftAnchor constraintEqualToAnchor:self.navigationItem.titleView.leftAnchor].active = YES;
//[self.searchBar.view.rightAnchor constraintEqualToAnchor:self.navigationItem.titleView.rightAnchor].active = YES;
[self.searchBar.view.centerXAnchor constraintEqualToAnchor:self.navigationItem.titleView.centerXAnchor].active = YES;
}
Expected result:
What I get (the title view is not centered):
View hierarchy:
What you're doing is both impossible and illegal. You are not making a "custom navigation bar item" at all (as claimed in your title). You are attempting to add a subview directly to a navigation bar. You can't do that. The way to put something into a navigation bar is to assign it into a view controller's navigationItem, either as a bar button item or as the navigation item's real titleView. (You call your variable titleView, but you are not in fact making it the navigation item's titleView.)
Here is my solution, changing only the title view, setting its width anchor to a fraction of the navigation bar's to make it responsive:
// Create search bar and set it as title view
self.searchBar = [SearchBar new];
self.navigationItem.titleView = self.searchBar.view;
// Turn auto constraints off
[self.searchBar.view setTranslatesAutoresizingMaskIntoConstraints:NO];
// Set the layout anchors
[self.navigationItem.titleView.widthAnchor constraintEqualToConstant:250.0].active = YES; // Had to set the width to a constant
// Was still causing problems
//[self.navigationItem.titleView.widthAnchor constraintEqualToAnchor:self.navigationController.navigationBar.widthAnchor multiplier:1.0/3.0].active = YES;// Still need to access the navigation bar's anchor
[self.navigationItem.titleView.heightAnchor constraintEqualToConstant:50.0].active = YES;

Adding MKMapView Causes Status Bar Issue in iOS 7

I'm solving the status bar issue in iOS 7 using
if(st.version == 7)
{
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = self.navigationController.view.frame;
frame.origin.y = 20;
frame.size.height = screen.size.height - 20;
self.navigationController.view.frame = frame;
}
Since I'm using navigation controller and pushing from one to another using [self.navigationController pushViewController:newone animated:YES];. It works fine in all view controllers. But, if the viewcontroller has mkmapview in xib, status bar issue of ios 7 occurs.
If I delete the mapview form xib and push to that view controller means, it will be like,
If I add the mapview even by code below,
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 100, 320, 100)];
[self.view addSubview:self.mapView];
It looks like,
How to solve this?
if(st.version == 7){
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 120, 320, 100)];
}else{
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 100, 320, 100)];
}
If you add mapView in viewWillAppear replace it in viewDidAppear.
Maybe you have this issue because you're doing manipulations with view's frames before your view is completely set up
I would highly suggest against doing it like that.
If you're using interface builder, then add constraints based on how you want your application to look and the frame will auto adjust itself.
If you're not using interface builder, then still use constraints, but get a good tutorial about making constraints programatically (as I don't know how to do it myself).
Edit: The reason I HIGHLY suggest not doing it with hardcoded numbers is that it'll be a pain to do iOS 6/7 Landscape/Portrait 3.5/4 inch screens. That's 8 cases.
i think you have some adjust your navigation Y position set -20px. that way it goes overlay. use this code your ViewController
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = self.navigationController.view.frame;
frame.origin.y =0;
frame.size.height = screen.size.height;
self.navigationController.view.frame = frame;
or may it you have use wantFullScreenLayout some where in your project
setWantsFullScreenLayout = YES:
statusbar section is located to the (0,0) point to catch.
Statusbar and as large as the size of the current view to increase the value of mainScreen change the size of the bounds.
Statusbar change the style of the translucent style.
this below link you get some clear idea about your issue
How do I get the navigation bar in a UINavigationController to update its position when the status bar is hidden?
Override the -edgesForExtendedLayout method in your view controller
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;
}
If you want to hide status bar from a particular view add this method in that particular view.m file
- (BOOL)prefersStatusBarHidden
{
return YES;
}
What about setting self.automaticallyAdjustsScrollViewInsets = NO; in viewDidLoad of your view controller or in IB?
Try to set MapView(ScrollView) automaticallyAdjustsScrollViewInsets = NO;
Try to set edgesForExtendedLayout to UIRectEdgeNone;
Try to use UIViewController.topLayoutGuide, see the Q&A from apple about this issue:Preventing the Status Bar from Covering Your Views.
Try to use the bar position delegation, see UIBarPositioningDelegate Protocol Reference
According to your description and screenshots, you are trying to move the whole UINavigationController.view.frame 20 pt, and the MapView(ScrollView) did something to prevent it happened (or re-set), put some breakpoint and log to track the frame of UINavigationController.view.frame changed.
Could you please provide a sample project? I'm so curious about what really happened.
try this
- (void)viewWillAppear:(BOOL)animated
{
self.navigationController.navigationBar.translucent = NO;
}
- (void)viewDidAppear:(BOOL)animated
{
self.navigationController.navigationBar.translucent = YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[application setStatusBarHidden:YES];
return YES;}
Please add this line to your code.This will hide the status bar from your app.
If you have a xib. Did you try to enabled Top Bar in simulated Metrics ?

iOS 7 UISearchBar right spacing

Don't know why, my search bar in iOS 7 is leaving a right space. It's ok in iOS 6.
I know it has something to do with the section index, because if I remove it the space disappears, but I don't know how to fix it. Any thoughts?
Embed your UISearchBar in a UIView and then add that as the tableHeaderView. Structuring it that way in a storyboard worked for me. I'm guessing iOS resizes the UISearchBar in the tableHeaderView, but leaves a basic UIView alone (and doesn't bother to look inside it).
You might also want to make the section index transparent, which I did with:
[[UITableView appearance] setSectionIndexBackgroundColor:[UIColor clearColor]];
[[UITableView appearance] setSectionIndexTrackingBackgroundColor:[UIColor clearColor]];
Until a better answer appears, I just manually changed the frame of the search bar like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGRect barFrame = self.searchBar.frame;
barFrame.size.width = self.view.bounds.size.width;
self.searchBar.frame = barFrame;
}
I had this same issue with the iPhone 6/ 6Plus when using a SearchDisplayController. (Using Swift)
I tried setting the frame of the search bar but with no luck but i noticed that if i tapped on the textField of the UISearchBar and then cancelled it then it would take on the proper size of the view. I therefore managed to fix the issue by calling the code below in ViewDidLoad of the viewController using the search.
self.searchController.setActive(true, animated: false)
self.searchController.setActive(false, animated: false)
self.contactsTableView.sectionIndexBackgroundColor = [UIColor clearColor];
The reason for that white edge is because your index layer has a white background and is on top of the search bar. This should be sufficient.
Add the search bar inside a UIView put as tableView's header view. Set the tableview's sectionIndexBackgroundColor to clear color because it covers the header.
Tested with iOS 7, 7.1;
Because the table view always leaves 15px on the right for section Indexes View, so you should resize the Seach bar after reloading the table view
First:
self.tblData.sectionIndexBackgroundColor = [UIColor clearColor]; //(iOS >= 7 only)
Cheating time:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
[self performSelector:#selector(resizeSearchBar) withObject:nil afterDelay:0.01];
}
- (void) resizeSearchBar
{
CGRect frame = self.searchBar.frame;
if (frame.size.width < self.tblData.frame.size.width) {
frame.size.width = self.tblData.frame.size.width;
}
self.searchBar.frame = frame;
}
- (void) reloadTableData // call it anytime you want to reload table view
{
[self.tblData reloadData];
[self performSelector:#selector(resizeSearchBar) withObject:nil afterDelay:0.01];
}
Suggest
Dont cheat like me, just do the simpler way:
self.searchBar.searchBarStyle = UISearchBarStyleMinimal; // iOS >= 7 only
I also attached a UISearcBar in my application, and nothing is wrong there even my application supports rotation also.
Could you try removing and re creating UISearchBar in storyboard/xib
I added the search bar as a subview of the top-level view instead of the table view. Used autolayout to pin the searchbar to the top guide, and a vertical space constraint of 0 between the search bar and the table view.
The accepted solution with the method viewDidLayoutSubviews makes the screen flicker.
Instead what I did was create a subclass of UISearchBar that simply does this:
FullWidthSearchBar.h:
#interface FullWidthSearchBar : UISearchBar
#end
FullWidthSearchBar.m:
#import "FullWidthSearchBar.h"
#implementation FullWidthSearchBar
- (void)setFrame:(CGRect)frame {
frame.size.width = self.superview.bounds.size.width;
[super setFrame:frame];
}
#end
And then I assigned that class to the search bar on my xib:
The problem is the right white block, so if we change the block color the same as the search bar background, it looks normal.
just
if (IOS7) {
self.tableview.backgroundColor = [UIColor colorWithPatternImage:self.searchBar.backgroundImage];
}

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
}

How to also animate subview in navigation bar?

I have a subview in my navigation bar. I try to add it by this way:
UIView *customView =
[[UIView alloc] initWithFrame:
CGRectMake(0, 0, image.size.width + label.frame.size.width, 44)];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[customView addSubview:imageView];
[customView addSubview:label];
[self.navigationController.navigationBar addSubview:customView];
However, when I try to push the navigation bar, the customView stays in the place, not animating following the sliding navigation bar. How can I achieve the animated subview? Is it even possible? Thanks!
you should not add subview in that way
you have tospecify your view location in the left , right or title view
self.navigationItem.titleView = YOURVIEW;
or choose another location left or right items in this way the the title view will added to the current view if you want to remove it just set it to nil in the place you want and reload it subviews again,
self.navigationItem.titleView = nil;
As you are using
[self.navigationController.navigationBar addSubview:customView];
that means the navigation bar you have create is in App delegate and is common for all the viewControllers in your project,that is why once you add a view on to it you see it on every view you have. Remove your sub-view in
-(void)viewWillDisappear:(BOOL)animated{
[Your subview remove fromSuperView];
[super viewWillDisappear:YES];
}
and add that subview in
-(void)viewWillAppear:(BOOL)animated{
[self.navigationController.navigationBar addSubview:Your subview];
[super viewWillAppear:YES];
}
this will add the subview in that particular view only and remove it as soon as that view is popped or pushed.The code given is not correct to the syntax please give a check on that.

Resources