Better to customize UINavigationBar with image or programmatically? - iphone

I know that there are two distinct ways to customize a UINavigationBar: you can either set the background image to some custom png, or you could customize the bar's appearance in code, programmatically. If my aim is to support iOS 4,5,6 does it make sense to try to customize the bar's appearance through code?
I essentially want a navigationbar without any gradience, a solid color, rounded corners, and an extremely thin shadow line. I would post an image below but I need at least 10 reputation points :(
I've started with the following code to address the no gradience and solid color issues, and I've placed this in the .m file of my rootviewcontroller before the #implementation of the class itself, but to no avail:
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
UIColor *color = [UIColor blueColor];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColor(context, CGColorGetComponents( [color CGColor]));
CGContextFillRect(context, rect);
}
#end
I also have implemented this code to round out the corners, which works:
CALayer *capa = [self.navigationController navigationBar].layer;
[capa setShadowColor: [[UIColor blackColor] CGColor]];
[capa setShadowOpacity:0.85f];
[capa setShadowOffset: CGSizeMake(0.0f, 1.5f)];
[capa setShadowRadius:2.0f];
[capa setShouldRasterize:YES];
//Round
CGRect bounds = capa.bounds;
bounds.size.height += 10.0f; //I'm reserving enough room for the shadow
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
[capa addSublayer:maskLayer];
capa.mask = maskLayer;
Any help on this matter would be greatly appreciated!

If you want to target iOS < 5 then the UIAppearance won't help you because it is supported only for iOS >= 5.
So in my opinion, using a png file for the navigation bar's background is faster and maybe safer. Depending on your desired result you can do it from code and also make it faster, just create a BaseViewController that will handle the navigation bar's appearance (background, title, buttons etc) and all your custom view controllers can inherit from this BaseViewController, but this implementation in some cases can has it's own drawbacks since you can't inherit from multiple classes in iOS, and I'm afraid that you will find out this a little bit late when you will get to a point when you will want to have features from a view controller that doesn't inherit from the BaseViewController.
On the other hand, creating the color and the graphics from code will probably raise issues from the beloved designers who will want 1px left/up/right/down/diagonal/etc, and in this way you will have headaches (happen to me).
If you are targeting iOS >=5 then UIAppearance is your friend.
So in conclusion, if you are targeting iOS >= 5 use UIAppearance if not, if you have a more complex (gradient, lines, strange colors) UI for your nav bar use png, if you have simple (one flat color) UI for nav bar, you can do it from code with no problems.

The appearance proxy of the UINavigationBar is there to set the default for ALL UINavigationBars if you want ALL of the bars to change then do it programmatically, if you want only 1 to change then do it in the storyboard both methods should have the same outcome for the appearance of your NavigationBar
The color/shadow should be with in the image, but be mindful of the fact that you shouldn't change the height of the navigation bar...
if you are able to have the image have the rounded corners and the shadow baked in
if you are not you will have to do it in code by using your code above
That is a simple method... a more advanced method would be creating a UINavigationBar item in your storyboard with an associated IBOutlet, setting an outlet to that item, set all the properties from with in the storyboard like the background image, then with in the viewDidLoad method set the IBOutlet of the UINavigationBar to the UINavigationBar of the UINavigationController of the UIViewController that you are loading. Also, you can round the corners of the UINavigationBar here if you desire.

Related

Custom UINavigationBar Height Issues

So I'm building an iOS application, and I customized my UINavigationBar to be taller than the default size. A couple problems have arisen, however.
My content acts as if the UINavigationBar is of the default height. This results in any views at y=0 to actually be hidden, or partially hidden, by my taller UINavigationBar. I have to manually place views the correct offset downward, which isn't a terribly huge issue, but I'm curious as to whether anyone has found a way to fix this. Essentially my UINavigationBar is being treated as a normal one with a larger background image.
Any views/buttons in my UINavigationBar are not tappable if the portion being tapped is below the typical 44px bottom of a normal UINavigationBar. Anything within the normal range works fine, but below that 44px mark it doesn't register. Again, it's as if my UINavigationBar is being treated by the application as one with a normal height but a large background image. This is a much more critical issue that I really need to resolve.
Here is the code that modifies my UINavigationBar:
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"navBarBackground_iPhone.png"] forBarMetrics:UIBarMetricsDefault];
[self.navController.navigationBar setBackgroundColor:[UIColor whiteColor]];
[self.navController.navigationBar setFrame:CGRectMake(0, 0, self.frame.size.width, 72)];
This is performed in my main window's -makeKeyAndVisible after my UINavigationController is allocated and initialized with a root view controller. The background image is 320px wide and 72px tall (double for the #2x version).
As you can see, I attempt to set the UINavigationBar's height here, after this portion of code it doesn't seem to stick. It reverts to 44px.
I've tried unsuccessfully to subclass UINavigationBar. Any help is greatly appreciated.
Try to subclass UINavigationBar and override the following method:
- (void)drawRect:(CGRect)rect
{
int heightYouWant = 100;
UIImage *image = [UIImage imageNamed:#"title_bar_bg.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, heightYouWant)];
self.tintColor = [UIColor colorWithRed:1/255.0 green:62/255.0 blue:130/255.0 alpha:1];
}
Add this method to your subclass of UINavigationBar:
- (void)layoutSubviews {
[super layoutSubviews];
CGRect barFrame = self.frame;
barFrame.size.height = heightYouWant;
self.frame = barFrame;
}

drawRect doesn't reflect changes made to layer

The UITableView I am using has a custom UItableViewCell. This custom cell has a subview (an UIView subclass) to it. I use the drawRect of the custom UIView subclass to place all the text to be displayed by the cell.
And in the drawRect (of UIView subclass) I do the following
/*
// This piece of code is called when setNeedsDisplay is called
*/
- (void)drawRect:(CGRect)rect
{
self.layer.cornerRadius = 10.0f;
self.layer.backgroundColor = [[UIColor orangeColor] CGColor];
self.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.layer.borderWidth = 3.0f;
}
However my custom cell is a black square like this
But I do see the intended behavior if I select the row. Like shown below
Whats going on ?
Your drawRect: method does not draw anything; the code that you put in there belongs in your initWithFrame: implementation.
You should manipulate the layer configuration in the initializer; in your drawRect: you should call functions of your CGContextRef based on the state of the view. For example, to draw some text you would use CGContextShowTextAtPoint, to draw some lines you would use CGContextAddLineToPoint, and so on.
See this question for information on the relationship between drawRect: and the CALayer of your UIView.
Try to set self.layer.masksToBounds = YES and (maybe) self.opaque = NO during your UIView's (the one where drawRect is overridden) initialization. (see this question)
Try to disable the selection highlight of the cell by using
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
You are doing one mistake:
Please go to the view in side the UItableViewCell and check the background color it may be black or something others, Reset it to clear color then check your result,

How to draw a line in interface builder in Xcode 4

I'd like to draw a simple inset line in Interface Builder to separate some items in a list and make the UI a bit more tidy. I don't see any "line" or similar objects in the objects library and can't seem to find any drawing commands in Interface builder.
I use a very narrow UIView with backgroundColor set to the appropriate color.
There are no lines in the iPhone UI library. This functionality on Max OS X was supplied by NSBox, but on the iPhone there is no corresponding UI element.
If you're afraid a UIView might affect performance, you can draw a line in code using CoreGraphics' CAShapeLayers.
Every UIView has a CALayer, so draw the line and add it to the views CALayer.
You can do this either in a custom UIView's drawRect or in your view controller:
(Make sure to add Quartz framework to your project)
UIBezierPath *linePath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0,self.view.frame.size.width, 1)];
//shape layer for the line
CAShapeLayer *line = [CAShapeLayer layer];
line.path = [linePath CGPath];
line.fillColor = [[UIColor blackColor] CGColor];
line.frame = CGRectMake(xPosition, yPosition, self.view.frame.size.width,1);
[self.view.layer addSublayer:line];
In place of view, why not just use a label and set the appropriate background color?
I used a view and made it narrow & changed the color to make it look like a line. But my issue is I am using the line on a vertical scrollview and the lines also get scrolled.
Interface Builder does not allow you to draw the shadows essential for an inset line. If you work with Photoshop you know this.
The following code will draw an "inset" if the line is in front of a white/beige Background.
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 1.0f)];
line.backgroundColor = [UIColor colorWithRed:(200.0f/255.0f) green:(200.0f/255.0f) blue:(200.0f/255.0f) alpha:1.0f];
line.layer.shadowColor = [UIColor darkGrayColor].CGColor;
line.layer.shadowOffset = CGSizeMake(0.0f, 1.0f);
line.layer.shadowRadius = 0.5f;
line.layer.shadowOpacity = 0.4f;
line.layer.masksToBounds =NO;
[Background addSubview:line];
Remember to import < QuartzCore/QuartzCore.h>.
As an alliterative - in Interface Builder, add a view who's height is set to 2 points. Wire up a IBOutlet to that view and set its layer border color and width:
self.mySeparatorLine.layer.borderWidth = 1.0f;
self.mySeparatorLine.layer.borderColor = [UIColor lightGrayColor].CGColor;
You can use Progress View as an option for a horizontal line. Just change the tint color and progress to 1 which is 100%.

Changing color of small portion of UIView?

I have a UIView whose color is black and opacity is 0.9 or something like that. What I want to do is to fill the UIView with black portion, but a specified rectangular area should not get black. i.e. that particular rectangular area remains with clear color...
Any kind of help will be appreciated.
regards,
Imran
You can subclass UIView and override - (void)drawRect:(CGRect)rect
And do something of the following (untested, but used something similar myself);
- (void)drawRect:(CGRect)rect {
// fill the whole UIView with a color
[[UIColor colorWithRed:1 green:1 blue:1 0.9] setFill];
UIRectFill( rect );
// draw a rect
CGRect rectIntersection = CGRectIntersection(theRectIWantToDrawIn, rect);
[[UIColor clearColor] setFill];
UIRectFill( rectIntersection );
}
The code above draws a black view with a simulated clearColor hole in it at a certain position. You could, of course, alter this behavior to your liking.
This is quite fast.
UPDATE: Do note that I set the UIView on which I want to draw the rect to UIClear color (I added it to a xib and set those properties there) and unchecked 'Opaque'. That should make the hole see-through.
UPDATE 2: My answer was based on this answer (credit where credit is due): iPhone - Draw transparent rectangle on UIView to reveal view beneath
Add another view (subview) to that area. And set its to your desired color. Thats the easy solution with your current requirements.
Or you can use some quartz core functions.
You can create a small UIView in the main view by custom and set background clear color
UIView *View1 = [[UIView alloc] initWithFrame:CGRectMake(128.0f, 50.0f, 34.0f, 34.0f)];
[View1 setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:View1];
[View1 release];

iPad "about" UI element

I would like to know how Apple built the about view. It looks like that text is inside UITableView element but the whole cell is scrollable.
My guess would be a UIWebView inside a custom table cell.
But that is just a guess. It could be a completely custom view, or various combinations of existing views.
No custom views are needed. All you have to do is configure the text view's layer appropriately. Here's a recipe that produces pretty much the effect you're looking for, assuming you have a UITextView in a view with light gray background:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
self.textView.clipsToBounds = NO;
CALayer *layer = self.textView.layer;
layer.cornerRadius = 10.0;
layer.borderWidth = 0.5;
layer.borderColor = [[UIColor grayColor] CGColor];
layer.shadowColor = [[UIColor whiteColor] CGColor];
layer.shadowOffset = CGSizeMake(0.0, 1.0);
layer.shadowOpacity = 1.0;
layer.shadowRadius = 0.5;
}
I had some trouble getting the white shadow to display. This SO question explains that you need to set clipsToBounds to NO in order to get the shadow to work.
Here's a picture of the result. I've shown the bottom corner so that you can see the white drop shadow.
Edit: I see now that the view in the question probably is, in fact, a UIWebView. I think it's possible to embed inline images in a NSTextView, but that's probably not the case with UITextView. Anyway, the recipe above should work as well for a UIWebView as it does for UITextView (or any other view).
You can achieve this with a stock UITextView; it's a subclass of UIScrollView, so you can just add the logo imageview as a subview. Then, make room for the image on top by adjusting the text padding:
textView.contentInset = UIEdgeInsetsMake(80,0,0,0);
If you have a tableview that has one section, one row, and the row has a view (UILabel or UITTextField) that is larger than the visible area on the screen, that would scroll like that. Or maybe just a UIScrollView with a UILabel in it.