adding shadow to bottom of UINavigationBar only - iphone

I have the following code:
self.navigationBar_.layer.shadowColor = [UIColor blackColor].CGColor;
self.navigationBar_.layer.shadowOpacity = 0.3f;
self.navigationBar_.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.navigationBar_.layer.shadowRadius = 3.0f;
self.navigationBar_.layer.masksToBounds = NO;
and I basically only want to add the border to the bottom only and not the entire rectangle. How do I do this? The code above will add a shadow to the left, right, top border also.

Instead of a layer shadow, you could just use a gradient. You could just use a transparent PNG gradient, but here is an example of how to do it programmatically:
UIView *topShadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.navigationBar.bounds.size.width, 10)];
CAGradientLayer *topShadow = [CAGradientLayer layer];
topShadow.frame = CGRectMake(0, 0, self.navigationBar.bounds.size.width, 10);
topShadow.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:0.0 alpha:0.25f] CGColor], (id)[[UIColor clearColor] CGColor], nil];
[topShadowView.layer insertSublayer:topShadow atIndex:0];
[self.view addSubview:topShadowView];

Related

UINavigationBar with two rounded corners

I have seen this answer
https://stackoverflow.com/a/9243472/563381
And while it works well visual as soon as you set the mask on the Navigation bar's layer it no longer responds to touches... So the back button that appears on the bar can't be clicked. Any solution to cause touches to go through a CALAyer? I didnt think CALayer's blocked touches or that a mask would ever block touches.
Well, I really don't know why CALayer blocks touches and this sounds odd to me...
The way I round corners of UINavigationBar consists in putting 2 UIImageView (10x10 pixels) in the corners and add 2 images to them. These images work as a mask, without blocking touches. If you use antialiasing to draw your images, the look is perfect.
You should try to use this code:
self.navigationController.navigationBar.translucent = YES;
This wil turn on your back button.You can see your button, but its in another layer. That's why it will not work the touches..
UPDATE:
Use this line of code for test. This will work like a charm for you.
//Style UINavigationBar
UIView *background = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
background.backgroundColor = [UIColor blackColor];
[self.view addSubview:background];
self.navigationController.navigationBar.tintColor = [UIColor cyanColor];
self.navigationController.navigationBar.translucent = YES;
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;
//Back Btn
UIButton *btnback = [UIButton buttonWithType:UIButtonTypeCustom];
[btnback setFrame:CGRectMake(0, 0, 54, 29)];
[btnback setBackgroundImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
UILabel * btnlabel = [[UILabel alloc]initWithFrame:CGRectMake(15, 0, 40, 23)];
btnlabel.backgroundColor = [UIColor clearColor];
btnlabel.textColor = [UIColor whiteColor];
btnlabel.font = [UIFont boldSystemFontOfSize:13];
btnlabel.text = #"back";
[btnback addSubview:btnlabel];
[btnback addTarget:self action:#selector(backHome:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:btnback];

NavigationBar layer gradient not working well

I am adding gradient to navigation Bar' layer and it is working fine.
Issue arrive when I push another view Controller and pop view Controller. Parent view Controller has right Bar Button Item whose color dims when I pop View Controller.
My code is
CGRect navFrame = self.navigationController.navigationBar.frame;
navFrame.origin.y = 0.0f;
[self.navigationController.navigationBar.layer insertSublayer:[AddGradient addGradientToNavigationBar:navFrame] atIndex:0];
code for addGradientToNavigationBar is
+ (CAGradientLayer*)addGradientToNavigationBar:(CGRect)navRect {
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = navRect;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0] CGColor],
(id)[[XAppDelegate getColor] CGColor], nil];
return gradient;
}
I have the same problem.
I was tying to add gradient layer to navigation bar with the UIBarStyleBlackTranslucent style for glass effect. After searching the web and a lot of experiments I have not found the right solution for that problem. Finally I've came up with following work around:
CAGradientLayer *yourGradient = ...
// Need two additional layers to mimic UIBarStyleBlackTranslucent style
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(0, 0, 320, 44);
NSMutableArray *cgColors = [[NSMutableArray alloc] init];
[cgColors addObject:(id)[[UIColor colorWithRed:0.0
green:0.0
blue:0.0
alpha:0.2] CGColor]];
[cgColors addObject:(id)[[UIColor colorWithRed:0.0
green:0.0
blue:0.0
alpha:0.6] CGColor]];
[cgColors addObject:(id)[[UIColor colorWithRed:0.0
green:0.0
blue:0.0
alpha:0.5] CGColor]];
gradient.colors = cgColors;
CALayer *layer = [CALayer layer];
_layer.frame = CGRectMake(0, 22, 320, 22);
_layer.backgroundColor =[[UIColor colorWithRed:0.0
green:0.0
blue:0.0
alpha:0.2] CGColor];
// This is needed for navigation bar buttons
[rootController.navigationBar setBarStyle:UIBarStyleBlackTranslucent];
// Adding layers to the first sublayer of the navigation bar layer
[[[rootController.navigationBar.layer sublayers] objectAtIndex:0] insertSublayer:yourGradient atIndex:0];
// After adding the gradient layer, the UIBarStyleBlackTranslucent style effect disappears
// from the bar (but not from the buttons)
// So the following is needed to mimic it
[[[rootController.navigationBar.layer sublayers] objectAtIndex:0] insertSublayer:gradient atIndex:1];
[[[rootController.navigationBar.layer sublayers] objectAtIndex:0] insertSublayer:layer atIndex:2];
you may also want to add some borders to your layer as the borders seems to disappear.

Change gradient for UIButton for different states

Recently I've encountered a problem. I have a UIButton and 2 images for it. 1 for normal state and 1 for highlighted. The problem is that normal state image is transparent and I should use gradient to fill it. But if I do it, my highlighted image never appears. Here's the part of the code:
UIImage *balloonImage = [[UIImage imageNamed:#"balloon.png"]resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
UIImage *balloonImageDown = [[UIImage imageNamed:#"balloon-down.png"]resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(0, 0, 320 - 45 - 10, 100);
gradient.cornerRadius = 3.0f;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:221.0f/255.0f green:231.0f/255.0f blue:246.0f/255.0f alpha:1.0f]CGColor], (id)[[UIColor colorWithRed:191.0f/255.0f green:207.0f/255.0f blue:234.0f/255.0f alpha:1.0f] CGColor], nil];
self.balloonButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.balloonButton.layer insertSublayer:gradient atIndex:0];
[self.balloonButton setBackgroundImage:balloonImage forState:UIControlStateNormal];
[self.balloonButton setBackgroundImage:balloonImageDown forState:UIControlStateHighlighted];
self.theImageView = [[[UIImageView alloc]init]autorelease];
[self.balloonButton addSubview:theImageView];
[self.contentView addSubview:balloonButton];
The gradient looks as it should and everything is working. Except for changing the image if the button is tapped.
Is there a way to put balloonImageDown in front of the gradient? Or how can I do that?
Any help would be appreciated.
[yourButton setTitleColor:[UIColor colorWithRed:0.3 green:0.6 blue:0.9 alpha:0.5]
// set 'alpha' to something less than 1. -----^^^
This is what you do to make it transparent.(changing the alpha value)
You should be changing these values in touchdown and touch up method.

UITableViewCell doesn't pickup UITableViewCellSelectionStyleBlue when adding CAGradientLayer sublayer

I have a UITableViewCell that I've added a gradient to by using CAGradientLayer. This works fine, but the table cell doesn't turn blue when selected, even after setting it's selectionStyle to UITableViewCellSelectionStyleBlue. If I don't add the gradient layer, it works fine.
Is there a way to make these items work together?
Here's my code inside of cellForRowAtIndexPath:
//cell gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(10, 0, 300, 50);
gradient.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1] CGColor],
(id)[[UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1] CGColor],
(id)[[UIColor colorWithRed:245/255.0 green:245/255.0 blue:245/255.0 alpha:1] CGColor],
(id)[[UIColor colorWithRed:247/255.0 green:247/255.0 blue:247/255.0 alpha:1] CGColor],
nil];
gradient.locations = [NSArray arrayWithObjects:
(id)[NSNumber numberWithFloat:0.00],
(id)[NSNumber numberWithFloat:0.50],
(id)[NSNumber numberWithFloat:0.51],
(id)[NSNumber numberWithFloat:1.0],
nil];
[cell.layer insertSublayer:gradient atIndex:0];
//bring back rounded corners by creating a masklayer
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:gradient.bounds byRoundingCorners:UIRectCornerBottomRight|UIRectCornerBottomLeft cornerRadii:CGSizeMake(8, 8)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = gradient.bounds;
maskLayer.path = maskPath.CGPath;
gradient.mask = maskLayer;
//add the cell shadow
cell.layer.shadowColor = [[UIColor blackColor] CGColor];
cell.layer.shadowRadius = 3;
cell.layer.shadowOpacity = 0.5;
cell.layer.shadowOffset = CGSizeMake(0, 0);
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
It looks like you might be putting the gradient over the view that changes when it is selected- the UITableViewCellSelectionStyleBlue view may be appearing, but you just cannot see it (a way to test it out is only have the gradient cover part of your cell- if the other part changes color when it is selected, then this is the issue).
If this is the issue, then you could do your own custom drawing for the cell when it is selected by subclassing UITableViewCell, or you could have the gradient disappear whenever the cell is selected (and reappear when the cell is deselected).

CAGradientLayer and scrollViewTexturedBackgroundColor

I'm trying to use CAGradientLayer to fade foreground controls against the background textured view.
So in a nutshell, I have a view with the bg color as scrollViewTexturedBackgroundColor. I have a view on top of that, whose contents I'd like to fade at the border into the background view's color.
CAGradientLayer* gradient = [CAGradientLayer layer];
gradient.frame = self->scrollableCanvas.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor scrollViewTexturedBackgroundColor] CGColor], (id)[[UIColor scrollViewTexturedBackgroundColor] CGColor], nil];
[gradient setStartPoint:CGPointMake(0.90, 1)];
[gradient setEndPoint:CGPointMake(1, 1)];
[[self->scrollableCanvas layer] addSublayer:gradient];
[[self->scrollableCanvas layer] setMasksToBounds:YES];
Unfortunately, CAGradientLayer doesn't seem to support UIColors as pattern images.
any ideas how I can achieve a simple border fade effect for the subview?
thanks
You can use a little trick:
//create normal UIImageView
UIImageView* iv = [[[UIImageView alloc] initWithImage: [UIImage imageNamed :#"bg_png.png"]] autorelease];
[superview addSubview: iv];
//draw gradient on top
UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite: 1.0 alpha: 0.0] CGColor], (id)[[UIColor colorWithWhite: 1.0 alpha: 1.0] CGColor], nil];
[view.layer insertSublayer:gradient atIndex:0];
[superview addSubview: view];
I made a category on UILabel that adds gradient at the end of the label using Max's answer.
If you need, here it is:
#import "UILabel+GradientEnding.h"
#implementation UILabel (GradientEnding)
- (void)addGradientEnding
{
//draw gradient on top
UIView *gradientAlphaView = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width - 80.0, 0, 80.0, self.frame.size.height)];
UIColor *startColor = RGBA(0xf7f7f7, 0);
UIColor *endColor = RGBA(0xf7f7f7, 1);
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = gradientAlphaView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[startColor CGColor], (id)[endColor CGColor], nil];
gradient.startPoint = CGPointMake(0, 0.5);
gradient.endPoint = CGPointMake(1.0, 0.5);
[gradientAlphaView.layer insertSublayer:gradient atIndex:0];
[self addSubview:gradientAlphaView];
}
#end
But you should use your own colors. And use this define:
#define RGBA(rgbValue, opacity) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:opacity]