UIView CAGradient with rounded corners?
Asked Answered
K

5

5

I have an UIView with rounded corners and drop shadow, implemented and working. But the UIView has a boring background color, white. So I want to put a gradient layer as the background. Below the labels, buttons and most important, make it so the rounded corners still appears.

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = subHudView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
[subHudView.layer addSublayer:gradient];
subHudView.layer.cornerRadius = 8;
subHudView.layer.masksToBounds = NO;
subHudView.layer.shadowOffset = CGSizeMake(-5, 5);
subHudView.layer.shadowRadius = 8;
subHudView.layer.shadowOpacity = 0.75;

This is my code as I tried to implement it, but the gradient layer is on top of everything in the view know. How can I make the gradient go under all the controls and labels? Every responding help will be appreciated.

Kherson answered 25/11, 2011 at 18:58 Comment(0)
H
1

When you addSublayer: it add the layer at the top of all the sublayers.

You should probably use something like that instead :

[subHudView.layer insertSublayer:gradient atIndex:0];

That way, the CAGradientLayer will be below everything else.

Highbrow answered 25/11, 2011 at 19:1 Comment(4)
Thanks, I've tried this before as well. But when I implement it the rounded corners disappear. Any thoughts on that? Edit I got it to work, just had to make the gradient have rounded corners too.Kherson
This is wrong. The gradient layer is still in front of your view's layer. It has to be: a sublayer is always is front of its superlayer. @Jacos might be able to make the new layer appear the way he wants, but he will not have made the gradient layer the actual background to his view, as he asked to do.Enjoin
Well, you might have a better answer (up voted), but this is not wrong. He wanted the gradient layer to go below the other label and controls, and my answer does what he asked.Highbrow
It is wrong. You said to say insertSublayer:atIndex:. That makes no difference whatever, and is just misleading to the OP. He was rounding the corners of the view's layer. Your code still puts the gradient layer in front of that.Enjoin
C
11

in Swift:

let gradientLayer = CAGradientLayer()
gradientLayer.cornerRadius = 20.0
Complexioned answered 26/11, 2018 at 14:41 Comment(0)
E
2

A layer added to your view (addSublayer) is drawn in front of your view's own layer, which is where all your view's drawing takes place. What you want is to draw the gradient into your view's own layer. To do so, implement +layerClass in your view, specifying that you want your view's layer to be a gradient view.

So, for example (in the view's own code):

+(Class)layerClass {
    return [CAGradientLayer class];
}

-(void)awakeFromNib {
    [super awakeFromNib];
    CAGradientLayer* layer = (CAGradientLayer*)self.layer;
    layer.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
    layer.cornerRadius = 8;
    layer.masksToBounds = NO;
    layer.shadowOffset = CGSizeMake(-5, 5);
    layer.shadowRadius = 8;
    layer.shadowOpacity = 0.75;
}

If you then implement drawRect:, however, you'll of course wipe out your gradient and your rounded corners. There are ways around that...

Enjoin answered 25/11, 2011 at 19:6 Comment(7)
Could you please show me an example on how to implement the +layerClass?Kherson
Okay, thanks! But self.layer gives me an error. It's not declared in my header file. How is it suppose to be?Kherson
Remember, I said that that code needs to be in the view's own code. You will need to create a UIView subclass in order to have a place to put it.Enjoin
But why is the method @gcamp posted wrong? Is there any downside using it?Kherson
@Jacos - The method isn't wrong. What he said is wrong. A view has its own primary layer and that layer can have subviews. You can draw the rounded rect, the shadow, and the gradient in the view's own layer, which is what I showed you how to do; or you can add a sublayer and draw the rounded rect, the shadow, and the gradient in that sublayer, as you are apparently now doing. It doesn't matter as long you understand what you're doing. His statement that you needed to use insertSublayer:atIndex: would tend to mar any such understanding.Enjoin
Thanks for clearing things out. I do understand and think I achieved the desired effect anyway, thanks. Will kind of promote my other question here... Would need an explanation to this: [link]#8283398Kherson
Yes, well, that really is a different topic. Everything you're doing here (using the layer to get rounded corners, gradient, shadow) is inefficient drawing. I was going to mention this, except that in your particular use in this question it doesn't matter. There's a good WWDC 2011 video on this topic (and 2010 too).Enjoin
H
1

When you addSublayer: it add the layer at the top of all the sublayers.

You should probably use something like that instead :

[subHudView.layer insertSublayer:gradient atIndex:0];

That way, the CAGradientLayer will be below everything else.

Highbrow answered 25/11, 2011 at 19:1 Comment(4)
Thanks, I've tried this before as well. But when I implement it the rounded corners disappear. Any thoughts on that? Edit I got it to work, just had to make the gradient have rounded corners too.Kherson
This is wrong. The gradient layer is still in front of your view's layer. It has to be: a sublayer is always is front of its superlayer. @Jacos might be able to make the new layer appear the way he wants, but he will not have made the gradient layer the actual background to his view, as he asked to do.Enjoin
Well, you might have a better answer (up voted), but this is not wrong. He wanted the gradient layer to go below the other label and controls, and my answer does what he asked.Highbrow
It is wrong. You said to say insertSublayer:atIndex:. That makes no difference whatever, and is just misleading to the OP. He was rounding the corners of the view's layer. Your code still puts the gradient layer in front of that.Enjoin
C
0

As well as the insertSublayer:atIndex: that gcamp suggested, you can also use insertSublayer:above: and insertSublayer:below: to place your layer in specific places.

[self.view.layer insertSublayer:gradient below:someUIObject];
Cartwell answered 25/11, 2011 at 19:6 Comment(0)
S
0

Rather than create a new layer, override your view's layer method:

+ (Class)layerClass
{
    return [CAGradientLayer class];
}

This will ensure that your view create a CAGradientLayer, rather than a basic CALayer, as the base layer.

Then, during init get hold of the layer:

CAGradientLayer *gradLayer = self.layer;
gradLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];

and assign your gradients to it.

Nice and clean...

Stonework answered 25/11, 2011 at 19:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.