iPhone groupTableViewBackgroundColor alternative for iPad - iphone

I am building an universal navigation app on iOS 5.0.
Setting the view backgroundcolor as below looks good for iPhone
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
But for iPad, i found out that this does not work as expected.
Is there any alternative to get same background on iPad using some color pattern?
If so ,please point me to some code samples or post some.

Recently when working on an XCode project we had set the background colour to groupTableViewBackgroundColor, which on an iPhone produces a pinstriped background, and works well. This background is the same one as used on UITableViews.
When porting this to iPad, the UITableViews now have a solid grey colour, and groupTableViewBackgroundColor essenitially is the same as [UIColor clearColor].
You would think that grabbing the colour that the UITableView uses would work. I am afraid it does not, as it turns out it is a slight gradient, not so much as you would notice, but when you're changing views, you notice.
The way to fix this is to create a CAGradientLayer, and apply it to a UIView before anything else loads.
First off, you need to create a function that emulates the gradient, below is what I used:
-(CAGradientLayer *)groupGradientColour {
CAGradientLayer *layer = [CAGradientLayer layer];
layer.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:(0xE2 / 255.0)
green:(0xE5 / 255.0)
blue:(0xE9 / 255.0)
alpha:1.0] CGColor],
(id)[[UIColor colorWithRed:(0xD0 / 255.0)
green:(0xD2 / 255.0)
blue:(0xD7 / 255.0)
alpha:1.0] CGColor],
nil];
layer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:1.0f],
nil];
return layer;
}
Then call this in viewDidLoad:
UIView *background = [[UIView alloc] init];
background.frame = CGRectMake(
0,
0,
[[UIScreen mainScreen] applicationFrame].size.width,
[[UIScreen mainScreen] applicationFrame].size.height);
CAGradientLayer *gradient = [self groupGradientColour];
gradient.frame = background.bounds;
[background.layer insertSublayer:gradient atIndex:0];
[self.view addView:background atIndex:0];
Once you have done this, you will have a gradient the same style as a UITableView.

Related

Problems with CAGradientLayer

Im using the code
NSArray *buttons = [NSArray arrayWithObjects: self.rollBtn,nil];
for(UIButton *btn in buttons)
{
btn.layer.shadowRadius = 3.0;
btn.layer.shadowOffset = CGSizeMake(-2.0, -3.0);
btn.layer.shadowOpacity = 0.5;
btn.layer.shadowColor = [UIColor blackColor].CGColor;
CAGradientLayer *btnGradient = [CAGradientLayer layer];
btnGradient.frame = btn.bounds;
btnGradient.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:102.0f / 255.0f green:102.0f / 255.0f blue:102.0f / 255.0f alpha:1.0f] CGColor],
(id)[[UIColor colorWithRed:51.0f / 255.0f green:51.0f / 255.0f blue:51.0f / 255.0f alpha:1.0f] CGColor],
nil];
[btn.layer insertSublayer:btnGradient atIndex:0];
}
But all i get is a button with a drop shadow. I've linked the quartz core library, ive imported it, i've linked the buttons, ive tried using different types of buttons; i'm Stumped.
Any Ideas whats going wrong?
Thanks in advance.
I faced same problem. It seems you are building for iOS6 as I do. I found that Autolayout for storyboards, introduced in iOS6, is causing such problems. Just disable it if you don't use this feature:
Open storyboard in Xcode
Open properties of storyboard (right pane with properties)
Uncheck "Use Autolayout" in "Interface Builder Document" section.
Did you try setting the locations and the start/end points for your gradient ?
btnGradient.locations = #[#(0.), #(1.)];
btnGradient.startPoint = (CGPoint){0., 0.};
btnGradient.endPoint = (CGPoint){0., 1.};
I think you could try to remove any previously existing CAGradientLayer in your button:
for(CALayer* layer in btn.layer.sublayers)
if ([layer isKindOfClass:[CAGradientLayer class]])
[layer removeFromSuperlayer];
and then adding your own.

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.

iOS CALayer memory leak only on device

The Instruments tool reports memory leak for CALayer. I have a custom class, a subclass of UIViewController; in the viewDidLoad() I instantiate a view with CAGradientLayer and insert this view as a subview of current view, e.g.:
UIControl *view = [[[UIControl alloc] initWithFrame:CGRectMake(10, 10, 460, 220)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0] CGColor],nil];
gradient.startPoint = CGPointMake(0, 0);
gradient.endPoint = CGPointMake(1, 1);
[view.layer insertSublayer:gradient atIndex:0];
view.layer.masksToBounds = YES;
[view.layer setCornerRadius:5];
[self.view insertSubview:view atIndex:1];
When I run the code in simulator, all is fine. However when I run it on device (iOS 4.3.3), the Instruments tool reports leaks for CALayer. When I coment out this code, there are no leaks.
What is the issue here?
Edit: I found out it only leaks if I insert the subview into a view which has a scrollview (so my subview with the gradient calayer is inserted between the view and scrollview).
release the
uiview and
layer
because simulator runs in system configuration so no problem will occur
but the device has less memory compared to system

replaceSublayer example

I have the following code and I can't seem to get it to work.
First I create a view with a layer.
UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
[view.layer insertSublayer:gradient atIndex:0];
Next I need to replace that layer. I have tried the following and it fails because I don't know how to access that layer 0. At this point I am in a different part of the program so I cannot just call gradient. I need to extricate it from view somehow.
[view.layer replaceSublayer:0 with:newgradient];
Apparently the 0 is supposed to be Old layer but I don't know how to access it.
Thanks.
I think you should be able to use this:
[view.layer replaceSublayer:[[view.layer sublayers] objectAtIndex:0]
with:newGradient];
I'm away from my Xcode development environment and can't test this at the moment though.
Keep a pointer to the gradient layer. If you have alot of them do it with an array.
If you still don't want to do that you can always use this to get an array of all the layers..
[self.layer sublayers];
Then you can cycle through and check some parameter to see if they are the same. Like set the layer.name to something when you create it.
Here is the function :
#define MyGradientLayerName #"MyGradient"
void makeViewGradient(UIView *pView,BOOL bRemoveBackground,CGColorRef clr1,CGColorRef clr2)
{
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.name = MyGradientLayerName;
gradient.frame = pView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)clr1,(id)clr2,nil];
CALayer *pGradientLayer = nil;
NSArray *ar = pView.layer.sublayers;
for (CALayer *pLayer in ar)
{
if ([pLayer.name isEqualToString:MyGradientLayerName])
{
pGradientLayer = pLayer;
break;
}
}
if (!pGradientLayer) [pView.layer insertSublayer:gradient atIndex:0];
else [pView.layer replaceSublayer:pGradientLayer with:gradient];
if (bRemoveBackground) pView.backgroundColor = nil;//free memory !
}

CABasicAnimation in a CAGradientLayer not working - what am I doing wrong?

I have a custom UITableView cell which has a button and a label. I fire a method when someone taps on the button, and then color that row. It's all working fine.
What I want to actually do is
user taps button, the row is colored in a gradient (it works now)
The gradient fades away
My code is below (BackView is the view in my custom cell)
CAGradientLayer *layer = [CAGradientLayer layer];
layer.frame = BackView.bounds;
UIColor *cOne = [UIColor paleYellowColor];
UIColor *cTwo = [UIColor whiteColor];
NSArray *colors = [NSArray arrayWithObjects:(id)cOne.CGColor,
cTwo.CGColor, nil];
layer.colors = colors;
NSNumber *stopOne = [NSNumber numberWithFloat:0.00];
NSNumber *stopTwo = [NSNumber numberWithFloat:0.8];
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];
layer.locations = locations;
CABasicAnimation *animateLayer = [CABasicAnimation animationWithKeyPath:#"colors"];
animateLayer.fromValue = [UIColor paleYellowColor];
animateLayer.toValue = [UIColor whiteColor];
animateLayer.duration = 3.0;
animateLayer.removedOnCompletion = YES;
animateLayer.fillMode = kCAFillModeBoth;
animateLayer.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[layer addAnimation:animateLayer forKey:#"animation"];
[BackView.layer insertSublayer:layer atIndex:0];
With this code, when I touch the button on the row, the background gets a gradient, but it never fades away, there's no animation - nothing. What am I doing wrong? I tried a few permutations and saw some examples, but none that helped me get this working.
Thanks!
When you animate a property with an explicit animation, you have provide the type that property is expecting. The colors property is animatable, however, you are giving it a UIColor for the from and to values. It's expecting an NSArray. Also, you need CGColorRefs for the colors themselves. I haven't tried it, but I'm thinking you need to change your to and from lines to:
animateLayer.fromValue = [NSArray arrayWithObjects:
(id)[[UIColor paleYellowColor] CGColor],
(id)[[UIColor whiteColor] CGColor], nil];
animateLayer.toValue = [NSArray arrayWithObjects:
(id)[[UIColor whiteColor] CGColor],
(id)[[UIColor whiteColor] CGColor], nil];
In theory, this should fade from your yellow/white gradient to white/white which should give the effect of fading out.
Best regards.