My client can't read iPhone's default fonts, the size is too small. I have an application with a navigation bar and I need to make everything in it bigger, for example, the font's size.
IB doesn't seem to allow this... any help?
Many thanks!
Update: today (2012) there is a much bigger tendency towards custom UIs, so I would say the answer below is way too harsh. There is still no supported way of customizing height, though, but you can certainly derive from UINavigationBar and override some sizing methods. This probably will not get you rejected (although it is still a grey area, just something Apple will probably overlook today).
Once you get the size you want, you can use iOS 5 customization APIs to add the custom background image (see WWDC 2011 Session 114 - Customizing the Appearance of UIKit Controls).
Original answer from 2009:
This is generally impossible.
What's more, I believe making the navigation bar taller is a violation
of Apple Human Interface Guidelines, and your application may be
rejected from the App Store because of it. Please make sure your
client understands this risk before proceeding.
(Pointing out rejection risks is usually a good way to convince
clients against making nonsense decisions.)
Many of the answers here are incorrect, or incomplete, so I wanted to add my answer here in the hope that it might enlighten some.
First off, there is nothing wrong with changing the height of the navigation bar. People commenting saying its not allowed, or goes against the guidelines are simply misunderstanding those guidelines.
The ability to adjust or alter the default navigation bar that's used inside a UINavigationController has been part of the SDK since iOS 5.
- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass NS_AVAILABLE_IOS(5_0);
The easiest way to change the height of the status bar is to use this method when initialising your navigation controller, passing in your custom UINavigationBar sub-class.
TestViewController *t = [[TestViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithNavigationBarClass:[MyNavigationBar class] toolbarClass:[UIToolbar class]];
[nav setViewControllers:#[t]];
[self.window setRootViewController:nav];
[self.window makeKeyAndVisible];
Where an example of such a custom UINavigationBar class could look like:
#interface MyNavigationBar : UINavigationBar
#end
#implementation MyNavigationBar
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize s = [super sizeThatFits:size];
s.height = 90; // Or some other height
return s;
}
#end
If you decided to just change the font size in the navigation bar, you can do this (usually in your UIViewController's viewDidLoad method):
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[titleLabel setBackgroundColor:[UIColor clearColor]];
// here's where you can customize the font size
[titleLabel setFont:[UIFont boldSystemFontOfSize:18.0]];
[titleLabel setTextColor:[UIColor whiteColor]];
[titleLabel setText:self.title];
[titleLabel sizeToFit];
[titleLabel setCenter:[self.navigationItem.titleView center]];
[self.navigationItem setTitleView:titleLabel];
[titleLabel release];
By subclassing you can achieve that and still support iOS 3+:
Complete example:
#import <UIKit/UIKit.h>
#interface ASNavigationBar : UINavigationBar
#property (nonatomic , retain) UIImage *backgroundImage;
#end
And implementation:
#import "ASNavigationBar.h"
#implementation ASNavigationBar
#synthesize backgroundImage = _backgroundImage;
-(void) setBackgroundImage:(UIImage *)backgroundImage
{
if (_backgroundImage != backgroundImage)
{
[_backgroundImage release];
_backgroundImage = [backgroundImage retain];
[self setNeedsDisplay];
}
}
-(void) drawRect:(CGRect)rect
{
// This is how the custom BG image is actually drawn
[self.backgroundImage drawInRect:rect];
}
- (CGSize)sizeThatFits:(CGSize)size
{
// This is how you set the custom size of your UINavigationBar
CGRect frame = [UIScreen mainScreen].applicationFrame;
CGSize newSize = CGSizeMake(frame.size.width , self.backgroundImage.size.height);
return newSize;
}
#end
Important notes:
If the background image is with transparent areas, you have to set its barStyle property to "translucent" or the transparent areas will be black.
If you have a NavigationBar taller than 44 points, you have to take into account that the position of the BarButtonItems might not be correct. They all will be anchored to the bottom of the bar. you can fix that by overriding layoutSubviews and change their origin.y value.
You should not change the height of the navigation bar. From Apple Programing Guide on View Controller:
Customizing the Navigation Bar Appearance
In a navigation interface, a navigation controller owns its UINavigationBar object and is responsible for managing it. It is not permissible to change the navigation bar object or modify its bounds, frame, or alpha values directly. However, there are a few properties that it is permissible to modify, including the following:
● barStyle property
● translucent property
● tintColor property
(taken from Apple: https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html)
UPDATE -- IOS 7 --- still only the available properties can be changed but below is a great tutorial on how to achieve flexibility in the navigation bar http://www.appcoda.com/customize-navigation-status-bar-ios-7/
To add to Skela's answer:
If you initiate your navigation controller in the Storyboard you can change the class of your UINavigationBar in the storyboard to your custom navbar.
and then implement the change height in the class
#interface MyNavigationBar : UINavigationBar
#end
#implementation SwitchAssessmentNavigationBar
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize s = [super sizeThatFits:size];
s.height = 200; // Or some other height
return s;
}
#end
Related
I have a problem with the display of my popover. After initWithContentViewController: and presentPopoverFromBarButtonItem:permittedArrowDirections:animated: it cuts corners of the navigation bar. How should I fix it?? Thanks.
This is the code I'm using
NavContr *nav = [NavContr new];
nav.navigationBar.backgroundColor = [UIColor redColor];
UIPopoverController *tempPop = [[UIPopoverController alloc] initWithContentViewController:nav];
[tempPop presentPopoverFromBarButtonItem:mainButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO];
EDIT: I have resolved this problem:
+ (void)configure:(UINavigationController *)navController {
UINavigationBar *navigationBar = navController.navigationBar;
UIView *contentView = nil;
for (UIView *view in navController.view.subviews) {
if ([[NSString stringWithFormat:#"%#", [view class]] isEqualToString:#"UILayoutContainerView"])
contentView = view;
}
// setting frame to navigation bar and content view
[navigationBar setFrame:CGRectMake(navigationBar.frame.origin.x, 0, navigationBar.frame.size.width, navigationBar.frame.size.height)];
[contentView setFrame:CGRectMake(contentView.frame.origin.x, 0, contentView.frame.size.width, contentView.frame.size.height + navigationBar.frame.size.height)];
[navController.view bringSubviewToFront:contentView];
for (UIView *customView in contentView.subviews)
customView.frame = CGRectMake(customView.frame.origin.x, customView.frame.origin.y + navigationBar.frame.size.height, customView.frame.size.width, customView.frame.size.height);
[contentView addSubview:navigationBar];
[contentView bringSubviewToFront:navigationBar];
}
This is probably because you have no root view controller, or are otherwise fiddling with the navigation controller in ways it was not meant to be played with. This is how you ought to be setting up the popover:
MyCustomViewController *viewController = [[UIViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil]; //or storyboard or whatever
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController]; //you should have a root view controller before displaying the popover
tintColor = [UIColor redColor];
UIPopoverController *tempPop = [[UIPopoverController alloc] initWithContentViewController:nav];
[tempPop presentPopoverFromBarButtonItem:mainButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO];
There are a few very important things going on here:
Your navigation controller should have a root view controller before you display it.
This code is using a standard UINavigationController instance. According to the documentation, you should not subclass UINavigationController, nor should you try and reinvent the wheel. Apple has created a complex and comprehensive framework, UIKit, that you can use to build amazing apps. If you try and step outside the box, you'll be creating an awful lot of work for yourself without any appreciable benefit.
This is using the tintColor property of the UINavigationBar class. If the tint is insufficient for your UI, you can also set the background image manually (refer to the docs).
If you want to make a popover with a navigation controller, use the built-in UINavigationController class. Don't subclass it and don't reinvent it. To customize the appearance of the navigationBar, use the UI_APPEARANCE_SELECTOR methods in the UINavigationBar class.
I get the solution before add CALayer the UIPopOverController shows like
after adding below lines in table view class i get the following UIPopOverController
#import <QuartzCore/QuartzCore.h>
CALayer *imageLayer2 = self.tableView.layer;
[imageLayer2 setCornerRadius:-20];
[imageLayer2 setBorderWidth:1];
Try it in your project may be it works!!
Thanx
I have tried & replicate the issue you are facing, made some R&D. It's due to the line of code below :
nav.navigationBar.backgroundColor = [UIColor redColor];
While you set the background color of the navigation bar it will behave weird due the native shape of the pop up. Try and remove the below line, you will definitely have issue resolved.
If you are specifying the Rect where the popover appears, we've found that using decimals can result in weird distortions like that. Be sure you're using whole number for origin and size.
I'm trying to reduce the brightness of my app at night, and while I have pretty good control over my UIView, the UITabBar and UINavigationController are giving me trouble.
How can I dim UITabBar and UINavigationController them without hiding them?
For the UITabBar you could do:
tabBar.alpha = 0.5
A UINavigationController is not a view, it is a controller, thus it doesn't make sense when you say you want to dim it. If you meant that you want to dim the UINavigationBar, you could do:
navigationController.navigationBar.alpha = 0.5;
Or if you want to dim everything in the navigationController:
navigationController.view.alpha = 0.5;
I would create a subclass of UIView that provides a solid black view. Next, you're going to have to pass touch events through the view so you will need to override -pointInside:withEvent:, return NO and pass the message up to the superview. Insert this view as a subview of the view you're trying to dim. Use the alpha property to control the dimming effect.
Edit I'm bored. Here's something I just threw together.
IADimmingView.h
#import <UIKit/UIKit.h>
#interface IADimmingView : UIView
- (id)initWithContainingView:(UIView *)view;
- (void)dim;
#end
IADimmingView.m
#import "IADimmingView.h"
#interface IADimmingView ()
#property (strong, nonatomic) UIView *containingView;
#end
#pragma mark -
#implementation IADimmingView
#synthesize containingView;
- (id)initWithContainingView:(UIView *)view
{
NSParameterAssert(view);
self = [super initWithFrame:view.frame];
if (!self)
return nil;
containingView = view;
self.backgroundColor = [UIColor blackColor];
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
[self.containingView pointInside:point withEvent:event];
return NO;
}
- (void)dim
{
[self.containingView addSubview:self];
}
#end
In your view controller, it is used like this...
IADimmingView *dimmingView = [[IADimmingView alloc] initWithContainingView:self.tabBarController.tabBar];
dimmingView.alpha = 0.75;
[dimmingView dim];
You may make them custom. This was asked many times here, for example: Custom colors in UITabBar
Just do the same with navigation bar.
This is how the navigationBar is declared in the documentation:
The navigation bar managed by the navigation controller. (read-only)
It is permissible to customize the appearance of the navigation bar using the methods and properties of the UINavigationBar class but you must never change its frame, bounds, or alpha values or modify its view hierarchy directly. To show or hide the navigation bar, you should always do so through the navigation controller by changing its navigationBarHidden property or calling the setNavigationBarHidden:animated: method.
This is the answer that I used to fix this: Visible buttons with transparent navigation bar
I am using the iPhone toolchain on Linux and so I have no Interface Builder. So how could I layout my view in my ViewController subclass? For example, I want a UITextView in the middle of the screen? Should I do this in the loadView or viewDidLoad. Do I also have to set the view for the ViewController subclass to itself?
It is not an easy job to layout all the view using code. Here are some code:
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake (100, 100, 100, 100)];
[self.view addSubview:textView];
The frame is the place (the first and second argument is x and y coordinator) and the size (the third and fourth argument is width and height of the text view).
Using this way, you can add any view into your class. Some of the view is built in and you don't have to draw yourself, some of them is not, and you need to subclass UIView and override drawRect.
You should do this in viewDidLoad when your main view controller is finished loading
I've written an open source project that does exactly this:
https://github.com/charlesmchen/WeViews
Here's another project that you might find useful:
http://code.google.com/p/layoutmanagers/
I usually build the entire view hierarchy in the loadView method and perform additional setup in the viewDidLoad, for example to set up the subviews content to reflect the data associated to the view controller. The important thing is to set the view controller view outlet in the loadView method.
#synthesize label; // #property(nonatomic,retain) UILabel *label declared in the interface.
-(void)loadView {
// Origin's y is 20 to take the status bar into account, height is 460 for the very same reason.
UIView *aView = [[UIView alloc]initWithFrame:CGRectMake(0,20,320,460)];
[aView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[aView setAutoresizeSubviews:YES];
// The 150x50 label will appear in the middle of the view.
UILabel *aLabel = [[UILabel alloc]initWithFrame:CGRectMake((320-150)/2,(460-50)/250,150,50)];
// Label will maintain the distance from the bottom and right margin upon rotation.
[aLabel setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin];
// Add the label to the view hiearchy.
[self setLabel:aLabel];
[aView addSubview:aLabel];
// Set aView outlet to be the outlet for this view controller. This is critical.
[self setView:aView];
// Cleanup.
[aLabel release];
[aView release];
}
-(void)viewDidLoad {
// Additional and conditional setup.
// labelText is an istance variable that hold the current text for the label. This way, if you
// change the label text at runtime, you will be able to restore its value if the view has been
// unloaded because of a memory warning.
NSString *text = [self labelText];
[label setText:text];
}
-(void)viewDidUnload {
// The superclass implementation will release the view outlet.
[super viewDidUnload];
// Set the label to nil.
[self setLabel:nil];
}
The biggest difficulty is probably understanding how IB settings map to UIView variables and methods, for example the autoresizing mask. Apple's UIView and UIViewController class references are full of useful informations.
When I receive a memory warning in my navigation based iPhone App the background image disappears in the previously allocated navigation controllers.
The background image is set as the background property of a UIView. This view is then added to the main window of the App delegate:
UIView *backgroundView = [[UIView alloc] initWithFrame: window.frame];
backgroundView.backgroundColor = [UIColor colorWithPatternImage:[[Utilities sharedManager] getImageWithName:#"Hintergrund2"]];
backgroundView.tag = 56789;
[window addSubview:backgroundView];
[backgroundView release];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
After I received the memory warning message and pressed the back button of the navigation controller the previous navigation controller shows up the normal Apple gray background. I have to navigate back to my home screen and navigate forward to "reset" the background image.
Can anyone tell me why the background disappears? It is not because of the image, when I set the background to a standard UIColor like blackColor the background (color) also disappears.
Thank you in advance for your help!
regards
Phil
It is undefined what the OS does with stuff added directly to the main UIWindow in case of low memory situations.
Maybe consider using a simple UIViewController for the background? You will then at least get callbacks when there is a low memory situation.
First, you should probably add your controller to the window like this:
window.rootViewController = navigationController;
I haven't tested this, but perhaps you can set the background color of the window directly:
window.backgroundColor = [UIColor colorWithPatternImage:[[Utilities sharedManager] getImageWithName:#"Hintergrund2"]];
If that doesn't work, you'll need a better way to recreate your view state in low memory situations. The most standard way to do this is by defining the background in each xib, which is reloaded. Alternatively, you could catch the low memory warning and recreate as needed by seeing if your backgroundView has a superview.
Make sure that you are setting the calling self.view.backgroundColor = [UIColor clearColor]; in the view controller's - (void) viewDidLoad otherwise the window's image will not be displayed.
- (void) viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
...
}
My problem was that I set the view's backgroundColor when it is initialized
MyTableViewController *myTVC =
[[MyTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
myTVC.view.backgroundColor = [UIColor clearColor];
and not in - (void) viewDidLoad.
In this situation, the UITableViewController's view's background color was set after it was initially created. However after a low memory warning, the UIViewController's that were not displayed have - (void) viewDidUnload called on them. That deallocate their views. Just before the UIViewController was to be displayed again, - (void) viewDidLoad was called and created a new view, but the view's background color was set to the default which is not clear.
How can I change the color of navigation bar from its default blue color?
Thanks.
The UINavigationBar class has a UIColor *tintColor property that you can change in code.
Alternately this property is also exposed in the InterfaceBuilder UI design tool.
Assuming you have added the navigation bar programmatically and not in Interface Builder, just put this in your viewDidLoad method.
self.navigationController.navigationBar.tintColor = [UIColor grayColor];
TintColor property doesn't affect default subview of navigation bar as bottom border and shadow. Sometimes it's useful to override layout of navigation bar at all.
Despite navigationBar is read-only property for UINavigationController you can avoid
this restriction by "setValue:forKey:". This method was approved on 5 applications successfully submitted to AppStore.
You can subclass UINavigationBar and change drawRect: method as you want.
For example,
#implementation CustomNavigationBar
- (void) drawRect:(CGRect)rect
{
[super drawRect:rect];
UIImage *backgroundImage = ImageFromColor(WANTED_COLOR);
[backgroundImage drawInRect:rect];
}
After you can subclass UINavigationController and change initWithRootViewController:
- (id) initWithRootViewController:(UIViewController *)rootViewController
{
self = [super initWithRootViewController:rootViewController];
if (self)
{
CustomNavigationBar *navBar = [CustomNavigationBar new];
[self setValue:navBar forKey:#"navigationBar"];
}
return self;
}
Also you can vary this approach by making Category for UINavigationController and implementing method swizzling for initWithRootViewController:
P.S. Yesterday my new app appeared at AppStore without any problem with this approach.