iOS7 UINavigationBar subclass > try to draw under UIStatusBar - uinavigationbar

I tried to draw a custom UINavigationBar via drawRect on iOS7. With the changes of the Navigationbar and the Statusbar my draw begins on y-origin 20.0, not on my 0.0 behind the Statusbar. I checked the wwdc videos but I only found examples with images not with custom draw. Any ideas? Do I need to set some parameters in my subclass?
create a new project based on "Master-Detail Application"
create a sublass for UINavigationBar
change the UINavigationBar in Main.storyboard to the custom class
turn off translucent [self setTranslucent:NO];
add a real simple drawRect to the sublass of UINavigationBar
I made a simple test:
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
UIBezierPath* maskPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, 320, 64)];
[maskPath closePath];
[[UIColor greenColor] setFill];
[maskPath fill];
CGColorSpaceRelease(colorSpace);
The green NavigationBar begins under the Statusbar, how can I draw by starting behind the Statusbar?
CURRENT SOLUTION:
#Redwarp posted one way, I made also a simple version to test:
CustomBGView *testView = [[CustomBGView alloc] initWithFrame:CGRectMake(0, 0, 320, 64)];
RetinaAwareUIGraphicsBeginImageContext(testView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[testView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBackgroundImage:image forBarPosition:UIBarPositionTop barMetrics:UIBarMetricsDefault];
Inside the custom UIView you can draw like you want and your custom view appears also behind the StatusBar.

I found a solution, which is a bit peculiar : I subclass the UINavigationBar, and in the onLayoutSubviews, I create the background I want to create, and set it as background image. So I do the equivalent of the drawRect, but in a UIImage that I set as background.
Then, in the xib or storyboard, I select my subclass as the type of the Navigation bar.
Here goes :
#implementation MyNavigationBar
- (void)layoutSubviews {
[super layoutSubviews];
CGPoint origin = [self.superview convertPoint:self.frame.origin toView:nil];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.bounds.size.width, self.bounds.size.height + origin.y), NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height + origin.y));
[self.baseImage drawInRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
// If you don't want the bar shadow, set the shadow image as null
[self setShadowImage:[UIImage new]];
}
And whenever you wan't to change the image, you call [navigationBar needsLayout], and it will call layoutSubviews again
EDIT : The trick is getting the origin of the nav bar. If there is a status bar, the origin will be of y 20. If no status bar, it will be 0. So you add the origin.y to the height of the image your drawing into, and you will have a nice result.

Related

UISearchBar barColor not matching UINavigationBar

I am setting the barColor of my UISearchBar to the same color that my navigation bar is set to. When I get back the results in the UI the colors do not match. I have translucent set to YES for both the searchbar and the navigation bar.
Can anyone tell me how I can get the color of the searchbar to match the nav bars color?
The easiest way I have found to accomplish this is by using an image instead of just a color.
[mySearchBar setBackgroundImage:[UIImage imageWithColor:[UIColor blackColor] forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
imageWithColor: is a category method I wrote on UIImage that looks like this:
+ (UIImage *) imageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Doing this, I am able to get the UISearchBar background to match the UINavigationBar background exactly.
You can just set the backgroundColor of the UISearchBar to UIColor.clearColor(). Then the barTintColor will come through as you expect.
I answered another SO question that is very similar to this one. Just setting translucent to NO won't do the trick. You have to slightly alter your color you use for the UISearchBar when you set it for the UINavigationBar. Check out my full answer here.

iOS - CGContextStrokePath/CGContextDrawPath remove black background color

I'm trying to draw a straight dashed line. I've gotten it so it draws the dashes, but this black background color remains. I've seem many answers to other questions, but none of them worked.
Apple's documentation seems to point to the fill color and using either CGContextFillPath or CGContextDrawPath, but neither of those work and the background of the dashed line is still black.
- (void)drawRect:(CGRect)rect {
CGContextRef contextRef = UIGraphicsGetCurrentContext();
GLFloat lines[] = {self.frame.size.width, self.frame.size.width*2};
CGFloat grey[4] = {0.6f, 0.6f, 0.6f, 1.0f};
CGContextSetStrokeColor(contextRef, grey);
CGContextSetFillColorWithColor(contextRef, [[UIColor clearColor] CGColor]);
CGContextSetLineDash(contextRef, 0, lines, 2);
CGContextSetLineWidth(contextRef, self.frame.size.width);
CGContextBeginPath(contextRef);
CGContextMoveToPoint(contextRef, 0, 0);
CGContextAddLineToPoint(contextRef, 0, self.frame.size.height);
CGContextDrawPath(contextRef, kCGPathFillStroke);
}
When manually adding this view to your view hierarchy, you just have to make sure you're setting the background color. For example, if you're initializing your view with initWithFrame, then set the background color in that method:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
Or, alternatively, when adding the view, set the background color there:
CustomView *customView = [[CustomView alloc] initWithFrame:frame];
customView.backgroundColor = [UIColor clearColor];
[self.view addSubview:customView];

How to remove border from some part of UIView?

I am having a UIView which contains other subviews. I am applying border to this UIView and the border is applied to the whole UIView. For that see the first image.
But do not want the border around the title where it says "Leaderboard". How can i remove the border for that portion only. See the below image and in that see that there is no border around the header Leaderboard..
NO,CALayer borders don’t support that behavior.
But you can try an alternate method if you need to implement this,
try adding an n-point-wide opaque subview with your desired border color as its background color, on each side of your main view.
Add this Code:
CGSize mainViewSize = theView.bounds.size;
CGFloat borderWidth = 2;
UIColor *borderColor = [UIColor redColor];
CGFloat heightfromTop = 25;
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, heightfromTop borderWidth, mainViewSize.height-heightfromTop)];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(mainViewSize.width - borderWidth, heightfromTop, borderWidth, mainViewSize.height-heightfromTop)];
leftView.opaque = YES;
rightView.opaque = YES;
leftView.backgroundColor = borderColor;
rightView.backgroundColor = borderColor;
[mainView addSubview:leftView];
[mainView addSubview:rightView];
This will add borders to both sides only.Repeat the same idea for top and bottom also.
NB : heightfromTop is the height of the top section where you don't want the border view to be present, you can alter it as per your needs
You can subclass the UIView and implement the drawRect like:
- (void)drawRect:(CGRect)rect
{
float borderSize = 3.0f;
//draw the bottom border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(0.0f, self.frame.size.height - borderSize, self.frame.size.width, borderSize));
//draw the right border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(0.0f,0.0f, borderSize,self.frame.size.height));
//draw the left border
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, CGRectMake(self.frame.size.width - borderSize,0.0f, borderSize,self.frame.size.height));
}
Now, you need to use the subclassed UIView for creating the needed view.

Remove the dark Line at the bottom of Navigationbar/Searchbar

I want to make a clean white Design. So, I set the tintColor property to whiteColor, but there are these dark Lines under the UINavigationBar and UISearchBar.
Do some one know, how to remove the dark Lines or how to change the Color?
add a method to UIImage by category
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
and just set
[self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:[UIColor whiteColor]]];
This is what I did, and seemed to work, it is a further development of this link. I changed the explicit width declaration to a dynamic one, so that it will be the size of the view if you change view size or not:
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, self.view.frame.size.width, 1)];
[overlayView setBackgroundColor:[UIColor whiteColor]];
[navBar addSubview:overlayView]; // navBar is your UINavigationBar instance
[overlayView release];
I found the stuff here:
How to remove UINavigatonItem's border line
From iOS 7 UINavigationBar has a shadowImage property that you can set to nil.

No Shadow/Emboss on UIBarButtonItem

I've got a problem with an custom UIBarButtonItem. When I create an custom UIBarButtonItem via
[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"FilterIcon.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(filterTouched:)];
the resulting button does not have the "embossed" look, that the system items achieve by placing a semi-transparent black shadow behind their icons.
On the left you see the "Organize" system bar button item, rightthe result of the code from above.
Creating the shadow in the resource is futile, because iOS/Cocoa only used the mask of the image and discards any color information.
Interestingly, if I create the bar button item in the Interface-Builder it looks fine. However, in the context of my problem, I need to create the button item in code.
There is Objective-C version of James Furey's script.
- (UIImage *)applyToolbarButtonStyling:(UIImage *)oldImage {
float shadowOffset = 1;
float shadowOpacity = .54;
CGRect imageRect = CGRectMake(0, 0, oldImage.size.width, oldImage.size.height);
CGRect shadowRect = CGRectMake(0, shadowOffset, oldImage.size.width, oldImage.size.height);
CGRect newRect = CGRectUnion(imageRect, shadowRect);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, oldImage.scale);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -(newRect.size.height));
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, shadowRect, oldImage.CGImage);
CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:0 alpha:shadowOpacity].CGColor);
CGContextFillRect(ctx, shadowRect);
CGContextRestoreGState(ctx);
CGContextClipToMask(ctx, imageRect, oldImage.CGImage);
CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:1 alpha:1].CGColor);
CGContextFillRect(ctx, imageRect);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I think the reason this occurs is covered by these answers to another question:
https://stackoverflow.com/a/3476424/1210490
https://stackoverflow.com/a/6528603/1210490
UIBarButtonItems behave differently depending on where you programmatically attach them. If you attach them to a toolbar, they'll become white "embossed" icons. If you attach them to a navigation bar, they won't.
I've spent the last few hours writing a function to apply toolbar UIBarButtonItem styling to UIImages. It's written in C# for MonoTouch, but I'm sure you'll be able to tweak it to Obj-C no problemo...
UIImage ApplyToolbarButtonStyling(UIImage oldImage)
{
float shadowOffset = 1f;
float shadowOpacity = .54f;
RectangleF imageRect = new RectangleF(PointF.Empty, oldImage.Size);
RectangleF shadowRect = new RectangleF(new PointF(0, shadowOffset), oldImage.Size);
RectangleF newRect = RectangleF.Union(imageRect, shadowRect);
UIGraphics.BeginImageContextWithOptions(newRect.Size, false, oldImage.CurrentScale);
CGContext ctxt = UIGraphics.GetCurrentContext();
ctxt.ScaleCTM(1f, -1f);
ctxt.TranslateCTM(0, -newRect.Size.Height);
ctxt.SaveState();
ctxt.ClipToMask(shadowRect, oldImage.CGImage);
ctxt.SetFillColor(UIColor.FromWhiteAlpha(0f, shadowOpacity).CGColor);
ctxt.FillRect(shadowRect);
ctxt.RestoreState();
ctxt.ClipToMask(imageRect, oldImage.CGImage);
ctxt.SetFillColor(UIColor.FromWhiteAlpha(1f, 1f).CGColor);
ctxt.FillRect(imageRect);
UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return newImage;
}
So, a UIBarButtonItem that used to look like this:
Created instead with the function above, like this:
UIBarButtonItem barButtonItem = new UIBarButtonItem(ApplyToolbarButtonStyling(UIImage.FromFile("MusicIcon.png")), UIBarButtonItemStyle.Plain, delegate {});
Would now look like this:
Hope this helps someone in the future.
Take note of the shadow offset in James Furey's script.
I've made the following experience:
float shadowOffset = 1.0f // for a UIBarButtonItem in UINavigationItem
float shadowOffset = 0.0f // for a UIBarButtonItem in UIToolBar
This was observed with iOS 6.1 SDK.
(Now obsolete under iOS 7)

Resources