The design I've been given for an iPhone app I'm working on calls for a 1px red line at the bottom of the navigation bar. I know how to draw a line with Quartz and -drawRect, but how do I get access to the UINavigationBar's view? Or would it work to draw the line in the app's main view, on top of everything else?
Duncan Wilcox's answer below works to get the line drawn, but then buttons on the bar become impossible to press.
If I do [self.navigationItem.titleView.superview sendSubviewToBack:titleView] then buttons that are created in nib files work, but not ones that are dynamically added.
I guess the answer depends on where you want the red line, as part of the navigation bar or just under it. That would be only 1 pixel difference, but designers are demanding these days :)
If you want it below the navigation bar you definitely have to put it in all of the app's views where the line is needed.
There's a surprisingly simple way to alter the look of the navigation bar, I used it for skinning the entire navbar look but it will probably work for even only some parts of the navbar if you make the image partially transparent.
Basically we want to skin the UINavigationItem of a UIViewController that's in your navigation hierarchy.
create a 320x44 image containing your custom navbar look
add a UIImageView to the XIB where the UINavigationItem is
link the titleView property of the UINavigationItem to the UIImageView
This almost works, except that the title view will be resized in wierd ways. To fix that I have a UIImageView subclass that keeps the image properly set:
#implementation TitleViewHack
- (void)setFrame:(CGRect)frame
{
frame.size.width = 320;
if(frame.origin.x > 0 && frame.origin.x < 20)
frame.origin.x = 0;
[super setFrame:frame];
}
#end
So instead of using a UIImageView above you'll use this TitleViewHack class.
This is what I've settled upon:
// UINavigationBar subclass
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"background_navbar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
Related
I'm very new to iOS programming.
I'm trying to set the toolbar background to a custom image.
I'm also using storyboards.
How do I go about that?
Do I edit UIToolbar in the UI Kit framework? Do I need to change something in Storyboard?
Thanks,
You can use UIToolbar's built-in -setBackgroundImage:forToolbarPosition:barMetrics: method:
// portrait
[yourToolbar setBackgroundImage:[UIImage imageNamed:#"YourToolbarBkg-Portrait.png"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
// landscape
[yourToolbar setBackgroundImage:[UIImage imageNamed:#"YourToolbarBkg-Landscape.png"] forToolbarPosition:UIToolbarPositionAny barMetrics: UIBarMetricsLandscapePhone];
YourToolbarBkg-Portrait.png will be 320x44 bkg image for portrait mode
YourToolbarBkg-Landscape.png will be 480x32 bkg image for landscape mode.
UIToolbar inherits from UIView. This just worked for me:
[topBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:BAR_BKG_IMG]] autorelease] atIndex:0];
UPDATED
topBar ------ is the outlet of the UIToolBar u are using
use this code where u are creating ur UIToolBar the class which implements the UIToolbar..
plus tell me y r u using Toolbar whats ur main purpose for it
Instead of editing UIToolBar, why not create a UIView of the same size and skin that however you would like? That would be easier if you are new.
Or if you want to override UIToolbar:
#implementation UIToolbar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"image.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
Had a right faff with background images for ToolBars and NavBars. I know setting the background image of a NavBar and ToolBar is generally a doddle. But, when you're presenting modal VC's, for some insane reason, where a NavBar is being added and you DO change the background image, it appears to double in size. Altering the height has strange results.
My issue was where I was using a NavController all over my App, but needed a modal view for one or two aspects of it. Simple enough. However, I needed either a NavBar or ToolBar type header with a Done button to pop the VC off the stack. Again, not an issue. But I needed the NavBar or ToolBar to look the same as everywhere else in my App.
I settled on a ToolBar, seeing as the VC was being presented modally. So, there my ToolBar sat, in typical Apple-blue. Nice, but not how the rest of my App looked, where a blackened image was being used for each NavBar. Using the iOS 5 appearance proxy, I altered the background image of the ToolBar. And this worked. But, unless I had the UIImage in exactly the proportions and size expected by the Tool Bar, I was in a pickle. The image simply did not look right at all. So, I decided to create a UIIMageView, where I could control the content mode, then insert a subview onto the toolBar.
Take a look at my code below.
UIImageView *toolbarImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:NAV_BAR_BACKGROUND]];
[toolbarImageView setFrame:[self.IBOToolBar bounds]];
[toolbarImageView setContentMode:UIViewContentModeScaleAspectFill];
[self.IBOToolBar insertSubview:toolbarImageView atIndex:1];
It's a bit of a fluff but I do hope this helps someone alter the image on their ToolBar.
NAV_BAR_BACKGROUND can be defined as follows:
#define NAV_BAR_BACKGROUND #"navBarBlackMattDarkSquare.png"
i am facing a new problem.
I have custom navigation controller in my application. I have to add an image to navigationbar and i used this code in my AppDelegate-
#implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"top-red.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, 44)];
}
#end.
This code is working fine for me, but when i use MFMailComposer in my application and call it on a button event i see that the navigationbar of MFMailcomposer is also changed to my custom navigationbar which i don't want to change.
Any Ideas!!!
By adding a category to the UINavigationBar, you are adding a method to all instances of UINavigationBar.
Since you are overriding drawRect: that means that whenever any navigation bar wants to draw itself it is using your method rather than the standard drawRect:
Rather than do this, you should just add the image to your navigation bars where you want them , rather than change it globally as you have done here.
It feels like this should be fairly simple but nothing i've tried so far has worked. In a nutshell, I want to add a fixed image just below the navigation bar in a UITableViewController that i create programmatically. In other words, I want the image to stay just below the navigation bar even as the user scrolls up and down the table view (it's basically a custom drop-shadow for the navigation bar).
The closest I've gotten is the code below (in the UITableViewController's init method), which adds the image but doesn't keep it from moving when the user scrolls.
// Add nav bar drop shadow
UIImage *dropShadowImage = [UIImage imageNamed:#"NavBarDropShadow.png"];
UIImageView *dropShadowView = [[UIImageView alloc] initWithImage:dropShadowImage];
[self.view addSubview:dropShadowView];
Is there an easy way to add an add an image to the screen programmatically, position it wherever you like, and have it stay there even as the user scrolls? Thanks for any and all input!
EDIT: IOS5 has a better way to do this. Please check out the new UIAppearance protocol.
Adding this block of code to your code will allow you to draw your shadow on all UINavigationBars in the app. This is a better solution than adding the shadow as a UIImageView:
#implementation UINavigationBar (ShadowBar)
- (void)drawRect:(CGRect)rect {
//draw the shadow ui nav bar
UIImage *image = [UIImage imageNamed: #"UINavBarWithShadow.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
- (void)layoutSubviews {
self.frame = CGRectMake(0, 0, self.frame.size.width, 300);
}
#end
To make the UINavigationBar higher and thus not clipping your content, override the layoutSubviews and set the frame you need (the code above assumes your header is 300 points high). layoutSubviews does nothing by default, but is "lazy" called before lay-outing the view.
For more info about this custom size/look overrides that apply to UIView (and any other subclass) have a look here
You can make a subclass or a category on UINavigationBar, and have it add the image in the init or drawRect methods. If you think about it, you're trying to add a shadow to the navigation bar, not to the UITableView, so it makes sense to modify the navbar, not the table.
You are adding your dropShadowView to self.view that in your case is the view of an UITableViewController. It means that your self.view is an UITableView so when you scroll up and down you scroll the dropShadowView as well because is inside the tableView.
Try to write a custom UIViewController and add two subviews: one is the dropShadowView and the other one is your table.
Have a look at this similar question I answered a while back. It should do exactly what you want with little customization.
Transparent View at the Top of a UITableView
Dont make a UITableView the main view ie. the view outlet, set that to a UIView that contains a UITableView, then make your controller a subclass of UIViewController, and make it conform to UITableViewDataSource and UITableViewDelegate. in your nib, set up your view so that you have a UIImageView at the top and a UITableView below. and set the delegate and datasource to your file's owner.
I am currently using this code in my App Delegate to set a custom background image for the Navigation bar:
#implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"MyNavigationBar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
It works great, and for all the views in my App I set the Navigation bar title to show no text (so it won't cover up the background image).
One of the views presents a modal view controller (an EKEventEditViewController to be exact), and the title in the Navigation bar says "Add Event", which shows up on top of my custom image.
I have tried several ways to change the title (to no avail), but would rather prevent the custom Navigation bar background image from showing up only in this modal view.
Does anyone know of a way to do this while still using the stated method for setting the Navigation bar background image?
please, never ever do this...
You are replacing the drawRect: method in UINavigationBar, very brittle and likely to cause you (and your users) headaches.
Your background will always show up in all instances of UINavigationBar because you have replaced the implementation of drawRect:
There is no way to replace the title of the EKEventEditViewController. Of course there is always a way, but its even worse than replacing the implementation of drawRect:
Instead, please make a subclass of UINavigationBar and use that in the places you require a custom nav bar.
I'm creating a custom progress bar and I've spliced it up into 1px images. If the progress bar were 100px wide then I would need 100 UIImageViews to fill the progress bar. The problem is this very quickly slows the iPhone down. How can I reuse an image view?
Anthony
Make your own UIView subclass and then draw the images onto it yourself in the drawRect message. Look at this
How to draw an UIImage or directly in -drawRect:?
Create The imageView in Xib (Not in View)
Create it's IBOutlet (Suppose Named MyImage)
And Try
For(int i=0;i<100;i++)
{
UIImageView *img=[[UIImageView alloc]init];
img.frame=CGRectMake(i,100,1,1);
img.image=MyImage.image;
[self.View addSubView:img];
}