CALayer shadow and translucent UINavigationBars - iphone

I've got a translucent navigation bar which is being rendered with a navigation controller.
I'd like to add a drop shadow underneath it, however, when the shadow is rendered, it seems to draw it inside the navigation bar too.
This is quite annoying, and I'd like to render the part of the shadow which is beneath the navigation bar.
Here's the code to render the shadow:
navController.navigationBar.layer.shadowColor = [[UIColor blackColor] CGColor];
navController.navigationBar.layer.masksToBounds = NO;
navController.navigationBar.layer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 320, 44)].CGPath;
navController.navigationBar.layer.shadowOpacity = 1.0f;
navController.navigationBar.layer.shadowRadius = 2.0f;
navController.navigationBar.layer.shadowOffset = CGSizeMake(0, 0);
navController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
Here's what I would like to achieve (created in an image editor):
However, here's what is actually rendered:
Any help appreciated.

[self.navigationController.navigationBar setTintColor:[UIColor colorWithRed:(132.0/255) green:(132.0/255) blue:(132.0/255) alpha:1.0]];
Try changing parameters as per your requirements.
Rather I would suggest to go with the linked approach will be beneficial as well as standard.
http://sebastiancelis.com/2009/12/21/adding-background-image-uinavigationbar/
source for that :
https://github.com/scelis/ExampleNavBarBackground

Related

Setting shadowImage On Translucent Navigation Bar

I am trying to set the shadowImage of the navigaion bar in my app delegate:
[[UINavigationBar appearance]setShadowImage:[UIImage imageNamed:#"navigation-bar-shadow"]];
This does not work by itself. It only works if I set the background image of the navigaion bar as well:
[[UINavigationBar appearance]setBackgroundImage:[UIImage new]forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
Here is my problem... the navigation bar is transluncent and I would like to keep it that way (no background images). But it seems that I cant set the shadowImage without setting the background image.
How can I set the shadowImage on translucent navigation bar?
Thanks!
Yes, you cannot set a shadowImage of a navigationBar without setting its backgroundImage :
See UINavigationBar Documentation :
For a custom shadow image to be shown, a custom background image must
also be set with the setBackgroundImage:forBarMetrics: method.
But you can render shadowImage invisible with empty image :
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc ]init]];
The response marked as an answer does not work if you want to keep the translucent effect in the NavigationBar.
A workaround I did was:
1) Create an Image with the color I wanted:
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
Then I assigned this as the backgroundImage to the UINavigationBar
[[UINavigationBar appearance]setShadowImage:[[UIImage alloc] init]];
[[UINavigationBar appearance]setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
Note that this makes the navigation bar fully transparent. Then I did the following to mimic the translucent 'blur' effect:
UIView *obfuscateView = [[UIView alloc] initWithFrame:CGRectMake(0,0,64,self.view.frame.width)];
[obfuscateView setBackgroundColor:[UIColor blueColor]];
[obfuscateView setAlpha:0.9f];
[self.view addSubView:obfuscateView];
The main thing here is you need to now add an additional view behind the navigationBar that will mimic the blur effect. This can be achieved with a minimal hit to performance by playing with alpha transparency rather than actually doing the calculations using a blurring view. Also note that this UIView needs to be of the same color.
What this allows you to do though is also play with gradients that have varying alpha to create a fading effect into the nav bar.

UIView subclass can't change from black background

I've created a subview of UIView to make some drawings - the drawings work fine in the drawRect method of my subclass, however, I cannot change the background color of the view. A little googling tells me I haven't set the frame for the view, but I'm not entirely sure how to do this. I tried two things:
I create the view in Storyboard and add it to my view controller, then declare it as a property in the header file and link them up. I synthesize the property at the top of the implementation file and in the viewDidLoad method, I add:
[myView setBackgroundColor: [UIColor whiteColor]];
The view's background is still black.
I also tried:
ViewSubclass *v = [[ViewSubclass alloc] initWithFrame: self.view.frame];
v.backgroundColor = [UIColor whiteColor];
myView = v;
To no avail.
What am I doing wrong?
UPDATE: This is the code I use to draw in the view, in case there's something going on there!
- (void)drawRect:(CGRect)rect {
CGFloat height = self.bounds.size.height;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGFloat barWidth = 30;
int count = 0;
for (NSNumber *num in samples) {
CGFloat x = count * (barWidth + 10);
CGRect barRect = CGRectMake(x, height - ([num floatValue] * height), barWidth, [num floatValue] * height);
CGContextAddRect(context, barRect);
count++;
}
CGContextFillPath(context);
}
It just creates a set of bars in the screen, of different heights.
CGContextClearRect From the docs:
If the provided context is a window or bitmap context, Quartz
effectively clears the rectangle. For other context types, Quartz
fills the rectangle in a device-dependent manner. However, you should
not use this function in contexts other than window or bitmap
contexts.
It might be that this clearing clears your entire view with no regard to the background color you set
I can t add comments due my low lvl, but the question springs to mind, have you added to your UIView to viewcontroller?
like
[self.view addSubview:v];
EDIT:
I'm sorry I had understood that the second option was added to the view that pragmatically.
Are you adding the view in the header file? If so you might need to be sure the frame's coordinates are visible and that the view is on top, also make the new view slightly smaller to see if it is actually being created:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[self.view addSubview: myView];
[self.view bringSubviewToFront:myView];
You can also change the main view background color to see if the new view is actually being created. For example:
[self.view setBackgroundColor:[UIColor grayColor]];
If the color is changing for your main view then the problem is that your new view is not being or brought to the front. Let us know how it goes!
At the point where do
[myView setBackgroundColor: [UIColor whiteColor]];
check to see if myView is not nil in the debugger

CALayer Border is appearing above subview (Z-order related, I think)

I have searched but could not find the reason for this behavior.
I have a UIButton whose image I am setting. Here is how the button should appear. Note that this is just a photoshop of the intended button design:
Essentially, it is a square custom UIButton with a white border and a little surrounding shadow. In the upper right corner, there is a "X" mark, that will be added programmatically as a subview.
Here is the screenshot of the button within the actual app. At this point, I have only added a shadow and the X mark as a subview:
How, when I try to add the white border, here is what it looks like:
It seems that the white border is appearing above the X mark sublayer. I don't know why.
Here is the code that I am using:
// selectedPhotoButton is the UIButton with UIImage set earlier
// At this point, I am adding in the shadow
[selectedPhotoButton layer] setShadowColor:[[UIColor lightGrayColor] CGColor]];
[[selectedPhotoButton layer] setShadowOffset: CGSizeMake(1.0f, 1.0f)];
[[selectedPhotoButton layer] setShadowRadius:0.5f];
[[selectedPhotoButton layer] setShadowOpacity:1.0f];
// Now add the white border
[[selectedPhotoButton layer] setBorderColor:[[UIColor whiteColor] CGColor]];
[[selectedPhotoButton layer] setBorderWidth:2.0];
// Now add the X mark subview
UIImage *deleteImage = [UIImage imageNamed:#"nocheck_photo.png"];
UIImageView *deleteMark = [[UIImageView alloc] initWithFrame:CGRectMake(53, -5, 27, 27)];
deleteMark.contentMode = UIViewContentModeScaleAspectFit;
[deleteMark setImage:deleteImage];
[selectedPhotoButton addSubview:deleteMark];
[deleteMark release];
I don't understand why the border is appearing above the deleteMark subview. Is there any way to get the intended effect?
Thank you!
From Apple's docs on CALayer:
The border is drawn inset from the receiver’s bounds by borderWidth. It is composited above the receiver’s contents and sublayers and includes the effects of the cornerRadius property.
In order to get the effect you want, I suggest you put the image into an own subview/sublayer and set that sublayer's borderWidth property.
You can set the layer's zPosition to -1. That worked for me.
I had similar problem (I wanted to prevent border line to be on top of my subviews)
CAShapeLayer * _border = [CAShapeLayer layer];
_border.strokeColor = [UIColor colorWithRed:119/255.0f green:119/255.0f blue:119/255.0f alpha:1.0f].CGColor;
_border.fillColor = nil;
[bgRoundView.layer addSublayer:_border];
_border.path = [UIBezierPath bezierPathWithRoundedRect:bgRoundView.bounds cornerRadius:20.f].CGPath;

How to programmatically render a flat background UIColor as the background for a UIToolbar?

So I followed a tutorial which allows me to subclass UIToolbar and draw an image as a custom background for the UIToolbar.
Code was something like this:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
UIImage *backgroundImage = [UIImage imageNamed:#"toolbar_background.png"];
[backgroundImage drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
This works flawlessly. Considering though that I just want my toolbar background to be a flat color. Basically something like [UIColor blackColor], is there an easier way to do this in the drawRect method?
Having to make a 320 x 44 px height flat black background image and use that with the above code seems like extreme overhead when [UIColor blackColor] is available? I'm just not sure how to implement it here.
I thought about doing something like this instead:
- (void)drawRect:(CGRect)rect
{
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.frame.size.width,self.frame.size.height)];
test.backgroundColor = [UIColor blackColor];
[self addSubview:test];
}
But this doesn't work because then the UIView COVERS all the UIToolbar items that I add later i.e the Toolbar is black yes, but the black is overtop all the toolbar items so they are not visible.
Is there a workaround?
Thanks.
You can create a flat UIToolbar without the need to create a subclass. Simply set BackgroundColor, BackgroundImage and ShadowImage.
[toolbar setBackgroundColor:[UIColor blackColor]];
[toolbar setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
[toolbar setShadowImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny];
Override the -drawRect: method as in your first example, but instead of drawing an image, use the UIRectFill method, like this:
[[UIColor blackColor] setFill];
UIRectFill(self.bounds);

UIButton not firing selector if I draw it using CALayer

Hi everybody I create this button like this:
_myButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
DLBadgeLayerDelegate *layerDelegate = [[DLBadgeLayerDelegate alloc] init];
_myButton.frame = CGRectMake(0.0 , 0.0, 100.0, 100.0);
[_myButton addTarget:self action:#selector(myButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
_myButton.layer.backgroundColor = [[UIColor redColor] CGColor];
_myButton.center = CGPointMake(10.0, 10.0);
[self addSubview:_myButton];
[_myButton release];
The button appears on the screen but if I tap on it nothing happens. If I just create a Rounded rect button instead with no custom drawing on its layer or if I just leave the layer line of code out all works well. Do you have any Idea why do I get this behaviour as I would like to do some custom drawing in the button's layer?
Events are not sent to a control that is (1) Hidden, (2) alpha < 0.1, (3) userInteraction=NO, etc. Since you have no button image, no button title, no background color, no background image, maybe it is being treated as transparent (like alpha < 0.1) and is not getting events. Try adding an image, title, or background color (in the UIView, not the layer) to see if that's the problem.
EDIT: Try putting the background color in the view's backgroundColor instead of in the layer's backgroundColor:
_myButton.backgroundColor = [UIColor redColor];
If I leave this line out:
_myButton.layer.backgroundColor = [[UIColor redColor] CGColor];
the event is triggered correctly and I still have no title, alpha, etc. I don't think that is the problem or explication, but I will try that way too.