I'm developing an iOS 6 and 7 app that requires the navigation bar to be taller than the usual 44/64 pts
I've searched high and low and so far it seems the cleanest solution is to use a category (or subclass) and implement the - (CGSize)sizeThatFits:(CGSize)size method to return a different size.
This works fine in just making , however doing this causes all the items inside to rest at the bottom of the navigation bar, while I'd like to have them centered.
I have tried using the Appearance Proxy protocol to define vertical offsets for the buttons, specifically this code
[[UIBarButtonItem appearance] setBackgroundVerticalPositionAdjustment: -10 forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundVerticalPositionAdjustment: -10 forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment: -10 forBarMetrics: UIBarMetricsDefault];
Works just fine on iOS 6, producing this result
But doesn't work on iOS 7, giving me this instead.
I have read around that under iOS 7 the adjustments only work when using custom views but it seems odd to me, especially considering that setBackButtonTitlePositionAdjustment:forBarMetrics: actually moves the text for the back button up, but not the chevron and that the title actually does nudge up.
I've also tried going for a subclassing route, using layoutSubviews to move down the views inside the UINavigationBar.
This works, but of course when a new view controller is pushed the buttons jump around during the transition.
Am I missing something? Thanks in advance
UPDATE I have edited the description to make it clearer that my issue is with what's inside the bar, not the bar itself.
The cleanest solution I've found to this problem was to use my own subclass of UINavigationBar and center the buttons vertically by overriding the layoutSubviews method:
- (void)layoutSubviews
{
[super layoutSubviews];
NSArray *subviews = self.subviews;
for (UIView *view in subviews) {
if ([view isKindOfClass:[UIButton class]]) {
view.frame = ({
CGRect frame = view.frame;
CGFloat navigationBarHeight = CGRectGetHeight(self.frame);
CGFloat buttonHeight = CGRectGetHeight(view.frame);
frame.origin.y = (navigationBarHeight - buttonHeight) / 2.0f;
frame;
});
}
}
}
To make a UINavigationController use your subclass of UINavigationBar you can use the initWithNavigationBarClass:toolbarClass: initialiser:
UINavigationController *navigationController = [[UINavigationController alloc] initWithNavigationBarClass:[MyNavigationBar class] toolbarClass:nil];
Did you try to add the following code to your viewDidLoad Method :
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
It is quickly explained in Apple migrating to iOS 7 Documentation : https://developer.apple.com/library/ios/documentation/userexperience/conceptual/TransitionGuide/AppearanceCustomization.html
//it's leave the status-bar height above.
There is a quick crack to this, unless you find the proper solution, this would definitely work ;)
Check for system running iOS7.
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
// Add below code
}
Add Label to the Navigation Bar :
UINavigationBar *bar = [self.navigationController navigationBar];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(110, 55, 150, 20)]; //Set the frame appropriate to your screen
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:14];
label.adjustsFontSizeToFitWidth = NO;
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor blackColor];
label.highlightedTextColor = [UIColor blackColor];
[bar addSubview:label];
Swift 3 version of Tiago his answer
override func layoutSubviews() {
super.layoutSubviews()
subviews.filter { (subview) -> Bool in
return subview is UIButton
}.forEach { (subview) in
subview.center.y = frame.height / 2
}
}
Adjusting the titleView vertical postion
setTitleVerticalPositionAdjustment(-10, for: .default)
You can change size of navigation bar with just changing it's frame:
CGRect navigationBarFrame = self.navigationController.navigationBar.frame;
Related
I have an issue with font size of UILabel, which is programmatically added in UIToolbar:
- (UILabel *)createTitleLabel
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(_topToolbar.frame)/3, CGRectGetHeight(_topToolbar.frame))];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor colorWithWhite:0.1 alpha:1.0];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont fontWithName:#"ArialMT" size:18];
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.8;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
// -----
UILabel *label = [self createTitleLabel];
self.titleLabel = label;
[self.topToolbar insertItem:[[UIBarButtonItem alloc] initWithCustomView:label] atIndex:_topToolbar.items.count/2 animated:NO];
// ------ code for adding item to toolbar
- (void)insertItem:(UIBarItem *)barItem atIndex:(NSUInteger)index animated:(BOOL)animated
{
NSMutableArray *toolbarItems = [self.items mutableCopy];
NSAssert(index <= toolbarItems.count, #"Invalid index for toolbar item");
[toolbarItems insertObject:barItem atIndex:index];
[self setItems:toolbarItems animated:animated];
}
After setting a bit large text to title label, it works as expected, font is reduced, and tail is truncated, but when I present UIAlertController, this font is getting larger, and UILabel width is growing, which hides other bar button items inside toolbar.
Beginning with iOS 11, views added to toolbars as UIBarButtonItem using customView initializer are now laid out using auto layout. You should add sizing constraints on your label. For example:
[label.widthAnchor constraintEqualToConstant:CGRectGetWidth(_topToolbar.frame)/3].active = YES;
[label.heightAnchor constraintEqualToConstant:CGRectGetHeight(_topToolbar.frame)].active = YES;
Otherwise, auto layout will use the intrinsic content size of your label which is causing the label.adjustsFontSizeToFitWidth = YES; to be ignored. Sizing likely works initially because adding a bar button item doesn't trigger a layout pass, however presenting and dismissing another view controller will cause auto layout to perform a pass for your view controller's entire view hierarchy.
For more information see the WWDC 2017 session Updating your app for iOS 11.
I saw a solution to change the height of navigation bar. But nothing worked for me. Now my application has one view controller connected with a navigation controller. I have not yet implemented any other code in my project. Before starting my project I need to change my height of my navigation bar.
edited:
.h:
- (CGSize)sizeThatFits:(CGSize)size ;
.m:
#implementation UINavigationBar (customNav)
- (CGSize)sizeThatFits:(CGSize)size {
CGSize newSize = CGSizeMake(370,40);
return newSize;
}
#end
UIView *NavView = [[UIView alloc] initWithFrame:CGRectMake(0, 0 , [UIScreen mainScreen].bounds.size.width , 44)];
NavView.backgroundColor = [UIColor clearColor];
NavView.userInteractionEnabled = YES;
[self.navigationController.navigationBar addSubview:NavView];
UIButton *DateBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 10, 90, 30)];
DateBtn.backgroundColor = [UIColor clearColor];
[DateBtn setTitle:#"Jan 05" forState:UIControlStateNormal];
DateBtn.titleLabel.font = [UIFont fontWithName:BrushScriptStd size:18];
[DateBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[NavView addSubview:DateBtn];
You can not change UINavigation height but you can add you custom view on UINavigation bar
Very simple solution to this problem is you can create view from StoryBoard or from Code.
And add the view to your viewController.
You have to disable default navigation Bar from you project. You can do it by Storyboard also. Select your navigation bar and change the Status Bar to none:
And If you want to do via code then in your didFinishLaunching wirte this code:
UIStoryboard *tStoryBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
RootVC* RootVCObj = [tStoryBoard instantiateViewControllerWithIdentifier:#"RootVC"];
UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:RootVCObj];
navC.navigationBarHidden = YES;
After this add as many as Buttons to your view
Main cons of this is that you have to make custom view for all Screens you currently have
I really need your help with this one (first post on SO -- be gentle):
I have two dynamic UIButtons which I would like to have centered in a UIView, which in turn should be centered in a UINavigationbar and UIToolbar. I can't - despite a lot of Googling - seem to figure out a proper way to do this.
This is what I've done so far:
In viewDidLoad, I add the two buttons as subviews and set the view as the UINavigationbar's titleView
self.myClass.viewForTitleAndButton = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 120, 32)];
[self.myClass.viewForTitleAndButton setBackgroundColor:[UIColor blackColor]];
[self.myClass.viewForTitleAndButton addSubview:self.myClass.myButton];
[self.myClass.viewForTitleAndButton addSubview:self.myClass.myOtherButton];
self.navigationItem.titleView = self.myClass.viewForTitleAndButton;
In a method being triggered when I press certain buttons, I set the title (and bounds) of one of the buttons depending on what's clicked:
CGSize titleSize = [title sizeWithAttributes:#{NSFontAttributeName : [UIFont italicSystemFontOfSize:17.0]}];
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat newX = (screenSize.width - titleSize.width) / 2;
CGRect buttonFrame = self.myClass.myButton.frame;
//Removing the line below doesn't do any difference at the moment
self.myClass.myButton.bounds = CGRectMake(newX, buttonFrame.origin.y, titleSize.width+8, buttonFrame.size.height);
[self.myClass.myButton setTitle:title forState:UIControlStateNormal];
NSLog(#"Title: %#", title);
//title is a NSString that changes depending on what is clicked. I am 100% sure it changes as I can see it in the log every time the method is triggered.
The problem is that the title of myButton is not changed. It worked before with the very same button when it was placed in a different spot and not as a subview.
Q1: What am I missing to make the title of the button change?
Q2: Is adding the buttons as subViews to a view that is then placed in the navigationbar and toolbar respectively a sound way to accomplish what I want?
This is really bugging me, any pointers in the right direction is much appreciated.
I don't think you can add a button which is already an outlet of a view controller. Thinking in another way, a button(view) can only has one superview.
Create button dynamically for the title view.
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *iv = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 160, 44)];
iv.backgroundColor = [UIColor greenColor];
titleButton = [UIButton buttonWithType:UIButtonTypeCustom];
titleButton.frame = CGRectMake(0, 0, 120, 44);
[titleButton setTitle:#"test" forState:UIControlStateNormal];
[titleButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[iv addSubview:titleButton];
self.navigationItem.titleView = iv;
}
//some event to change the button title
- (void)click:(UIButton *)button
{
[titleButton setTitle:#"I changed" forState:UIControlStateNormal];
}
I'm adding a UIScrollView to a UIViewControllers view. For some reason, between adding the scroll view to the view and it getting displayed, the contentOffset is set to {0, -64}, 64 being the status bar's 20 plus the navigation bar's 44 points (I guess). Below is some code that reproduces the issue, and an image.
How do I prevent iOS from setting the contentOffset?
- (void)viewDidLoad
{
[super viewDidLoad];
_scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(10, 100, 100, 100)];
_scroll.backgroundColor = [UIColor greenColor];
_scroll.delegate = self;
UIView *red = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
red.backgroundColor = [UIColor redColor];
[_scroll addSubview:red];
[self.view addSubview:_scroll];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// outputs {0, -64}
NSLog(#"%#", NSStringFromCGPoint(_scroll.contentOffset));
}
Set automaticallyAdjustsScrollViewInsets on your view controller to NO, otherwise it'll adjust insets on the first subview of it's root view that happens to be of UIScrollView class.
More on this in iOS 7 Transition Guide.
For iOS 11+, set UIScrollView's contentInsetAdjustmentBehavior = .never to prevent the system from adjusting contentOffset automatically when it's being added to another view
I have a UITableViewController with a UISearchDisplayController and UISearchBar. I'm seeing a white line under the navbar when I present the view in a UITabBarController. When I present the view modally in a UINavigationController, the line is either gray or black (I can't tell) and it looks perfectly normal. Any ideas?
I had the same problem, couldn't figure out from where it did came from (it was present everywhere and it was NOT the shadowImage), ended up with the following fix (in my UINavigationController subclass)
// Fixes strange line under NavigationBar
{
UIView * view = [[UIView alloc] init];
view.backgroundColor = self.navigationBar.barTintColor;
CGRect rect = view.frame;
rect.origin.x = 0.f;
rect.origin.y = self.navigationBar.frame.size.height;
rect.size.width = self.navigationBar.frame.size.width;
rect.size.height = 1.f;
view.frame = rect;
[self.navigationBar addSubview:view];
}
I had the same problem too, after trying with a lot of methods,I find this way solved my problem
[[UISearchBar appearance] setBackgroundColor:[UIColor yourColor]];
write it in your viewDidLoad.
The white line is probably the shadowImage of navigation bar.
Try setting it as:
self.navigationController.navigationBar.shadowImage = [UIImage new];
Try setting the clipsToBounds property on the UISearchBar to YES.
Use following line of the code :
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, 320, 1)];
[overlayView setBackgroundColor:[UIColor whiteColor]]; // set color accordingly
[navBar addSubview:overlayView]; // navBar is your UINavigationBar instance
[overlayView release];
here is my posted Answer :
Horizontal Separator NavBar IOS 7
How to remove UINavigatonItem's border line
Swift version of Divya's answers
let hideLineView = UIView(frame: CGRect(x: 0, y: navigationController!.navigationBar.frame.size.height, width: view.frame.size.width, height: 1))
hideLineView.backgroundColor = UIColor.white
navigationController!.navigationBar.addSubview(hideLineView)