How to resize a CAGradientLayer after rotation? - ios

I'm adding a CAGradientLayer to a view. When the view is auto-resized (such as after a rotation) the gradient layer is not resized. Can the gradient be set to auto-resize the same as the view? Note also that I am using auto-layout constraints in the view.
Here's what I'm doing:
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0.0, 0.0, frame.size.width, frame.size.height);
gradientLayer.colors = [NSArray arrayWithObjects:
(id)[[UIColor colorWithRed:255.0/255.0f green:255.0/255.0f blue:255.0/255.0f alpha:1.0f] CGColor],
(id)[[UIColor colorWithRed:233.0/255.0f green:233.0/255.0f blue:233.0/255.0f alpha:1.0f] CGColor], nil];
[self.layer insertSublayer:gradientLayer atIndex:0];

Here are two different ways to fix your problem.
Make gradientLayer an instance variable instead of a local variable. Then, override layoutSubviews in your view class to set the frame of the gradient layer:
- (void)layoutSubviews {
[super layoutSubviews];
_gradientLayer.frame = self.bounds;
}
Create a subclass of UIView named GradientView, and override its +layerClass method to return [CAGradientLayer class]. Use this view to draw your gradient instead of using a layer directly. Then set the gradient view's autoresizingMask (or add constraints to it if you are using auto layout). See this answer for an example.
Creating the GradientView class will also make the resizing behave correctly during rotation, so I recommend that solution.

I resize the layer's bounds manually by overriding the setFrame: method of the view:
-(void)setFrame:(CGRect)frame
{
[super setFrame:frame];
_gradientLayer.bounds = CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));
}

Related

UITableViewCell Gradient Layer Covering Delete Button

I'm using this answer to create a gradient background for a table view cell
How to make gradient background in UITableViewCell in iOS?
-(void)addGradientBackgroundWithColor:(UIColor *)color {
if (!self.gradientLayer) {
self.gradientLayer = [CAGradientLayer layer];
self.gradientLayer.frame = self.bounds;
self.gradientLayer.startPoint = CGPointMake(0.0f, 0.5f);
self.gradientLayer.endPoint = CGPointMake(1.0f, 0.5f);
}
self.gradientLayer.colors = #[(id)[[color hmf_makeLightHighlight] CGColor], (id)[[UIColor whiteColor] CGColor]];
[self.layer insertSublayer:self.gradientLayer atIndex:0];
}
The problem is that when I do a swipe to delete gesture, the gradient layer seems to cover the delete button.
Is there a way to fix this?
Adding this fixed my issue
- (void)layoutSubviews {
// resize your layers based on the view's new bounds
self.gradientLayer.frame = self.bounds;
}
I guess that you insert gradient layer into UITableViewCell. I think insert into contentView of UITableViewCell may solve your problem.

CAGradientLayer cannot change color

I want a colored gradient to overlay my view. In a view controller, I have this code
- (void)viewDidLoad {
self.view.backgroundColor = [UIColor whiteColor];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.view.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColor redColor].CGColor, (id)[UIColor clearColor].CGColor, nil];
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(0, 1.0f);
self.view.layer.mask = gradientLayer;
}
But even though the first color is red, I only ever see a black gradient. How can I display a red gradient instead?
TLDR: Instead of setting the gradient as the layer mask, add the gradient layer as a sublayer of view.layer.
Layers use the layer mask mask to determine the alpha of their own content by using the alpha of the mask at each pixel, since your gradientLayer is fully opaque, the effect you were getting wasn't the one you were hoping for.
Layers are similar to views (views are actually wrappers for layers), you can add them as sublayers in a similar way that views are added as subviews.

CAGradientLayer for only background

I am setting gradient to background of my view:
CAGradientLayer *grad = [CAGradientLayer layer];
grad.frame = self.contentView.frame;
grad.colors = #[(id)[[UIColor colorWithRed:1.0f green:0.5f blue:0.5f alpha:0.0f] CGColor],
(id)[[UIColor colorWithWhite:1.0f alpha:0.5f] CGColor],
(id)[[UIColor colorWithWhite:1.0f alpha:0.8f] CGColor],
(id)[[UIColor colorWithWhite:0.0f alpha:1.0f] CGColor]];
grad.locations = #[#0.00f, #0.5f, #0.7f, #1.00f];
self.layer.mask = grad;
Problem is, that every element (UIButton, UILabel...) on top of my view has that then same gradietn as parent. How can I set gradient only for view and not for items, that are on this view ?
Instead of setting the mask, you can set the gradient as sublayer of your view as below:
[self.view setBackgroundColor:[UIColor clearColor]];
[self.view.layer insertSublayer:grad atIndex:0];
That is what a mask is supposed to do. :-)
You can work with a dedicated background view that is not superview (but probably sibling) to the other views that are drawn on top of it.
When you don't use it as superview of subviews but as sibling to siblings (all share the same superview) then the sequence is of importance. Make sure that the background view is drawn first. That is in IB when it is located above of the "subviews" in the view hierarchy tree but within the same level.

making drop shadows on UIViews

I use this code in my customized UIView initialization:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
...
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(frame.origin.x, frame.size.height, frame.size.width, 15)];
self.layer.masksToBounds = NO;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
self.layer.shadowOpacity = 0.5f;
self.layer.shadowPath = shadowPath.CGPath;
}
return self;
}
trying to make a drop shadow like this:
1)
But I got this effect:
2)
You can see this is an upside down version of what I want to achieve. How to make the shadow effect of the first image?
The issue is just with your shadowPath.
Using CGRectMake(frame.origin.x, frame.size.height, frame.size.width, 15) to create your UIBezierPath will set an incorrect origin.
First, origin.x should be 0.0f or the shadow will shift far away if your UIView's origin.x != 0.0f. Second, you need to line up the bottom of the shadowPath with the bottom of your UIView.
This is a screenshot of UIViews using your shadow code illustrating these issues. (In the lower UIView you cannot see the shadow because it is far off the right of the screen).
You will see what you intended if you change the rect to:
const CGFloat shadowRectHeight = 15.0f;
CGRect shadowRect = CGRectMake(0.0f, self.bounds.size.height - shadowRectHeight, self.bounds.size.width, shadowRectHeight)];
Do like this and set the UIView alpha
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = rect;
gradient.colors = [NSArray arrayWithObjects:(id)[UIColor blackColor].CGColor,
(id)[UIColor grayColor].CGColor,
(id)[UIColor blackColor].CGColor,nil];
[self.layer insertSublayer:gradient atIndex:0];
you can add or remove UIColor you want to display.

UIView Gradient using CAGradientLayer always blue

I am trying to create a UIView with a dark gray gradient:
UIView *sectionSpacer = [[UIView alloc] init];
sectionSpacer.backgroundColor = [UIColor clearColor];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = sectionSpacer.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[RGB(80, 83, 88) CGColor], (id)[RGB(69, 71, 73) CGColor], nil];
[sectionSpacer.layer addSublayer:gradient];
For some reason the gradient view is always blue even thought the RGB values are dark grays. Why is this?
If you just init the view without a frame, it'll default to CGRectZero, so your layer will also have 0 width and height, which is why you don't see it (the gradient you do see looks like a standard UITableView header that may come from elsewhere, I doubt that it is even the same view you're initializing in the code you've shown).

Resources