Objective C - Faded Gradient on left/right sides of UICollectionView - objective-c

I have a horizontal-scrolling UICollectionView within the main view of a view controller like so (Grey is UIView, Wood is UICollectionView):
I want to add fixed faded gradients on the far left & far right sies of this UICollectionView so that the scrolls appear to vanish as the user scrolls. How would I go about doing this? Does it involve some use of CAGradientLayer? I would be grateful for any help you can give me!

I actually managed to figure this out using one mask layer thanks to this tutorial at cocoanetics. Here's what I did:
#interface ScalesViewController : UIViewController
{
CAGradientLayer *maskLayer;
}
#end
Then in the .m, I placed in the following:
- (void)viewDidAppear:(BOOL)animated
{
[super viewWillAppear: animated];
if (!maskLayer)
{
maskLayer = [CAGradientLayer layer];
CGColorRef outerColor = [[UIColor colorWithWhite:0.0 alpha:1.0] CGColor];
CGColorRef innerColor = [[UIColor colorWithWhite:0.0 alpha:0.0] CGColor];
maskLayer.colors = [NSArray arrayWithObjects:
(__bridge id)outerColor,
(__bridge id)innerColor,
(__bridge id)innerColor,
(__bridge id)outerColor, nil];
maskLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.125],
[NSNumber numberWithFloat:0.875],
[NSNumber numberWithFloat:1.0], nil];
[maskLayer setStartPoint:CGPointMake(0, 0.5)];
[maskLayer setEndPoint:CGPointMake(1, 0.5)];
maskLayer.bounds = self.mainCollectionView.bounds;
maskLayer.anchorPoint = CGPointZero;
[self.mainCollectionView.layer insertSublayer: maskLayer atIndex: 0];
}
}
This creates a nice "fade to black" effect on both sides of my collection view. More colors can be added to the locations & color properties to refine the gradient blend. The start/endpoints determine the direction and location of the gradient.

Try to add two layers of CAGradientLayer on the collection view sublayer:
#import <QuartzCore/QuartzCore.h>
CAGradientLayer *leftShadow = [CAGradientLayer layer];
leftShadow.frame = CGRectMake(0, 0, 100, self.collectionView.frame.size.height);
leftShadow.startPoint = CGPointMake(0, 0.5);
leftShadow.endPoint = CGPointMake(1.0, 0.5);
leftShadow.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:0.0 alpha:0.4f] CGColor], (id)[[UIColor clearColor] CGColor], nil];
[self.collectionView.layer addSublayer:leftShadow];
CAGradientLayer *rightShadow = [CAGradientLayer layer];
rightShadow.frame = CGRectMake(CGRectGetWidth(self.collectionView.frame)-100.0, 0, 100, self.collectionView.frame.size.height);
rightShadow.startPoint = CGPointMake(1.0, 0.5);
rightShadow.endPoint = CGPointMake(0, 0.5);
rightShadow.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:0.0 alpha:0.4f] CGColor], (id)[[UIColor clearColor] CGColor], nil];
[self.collectionView.layer addSublayer:rightShadow];

Related

Add gradient color on every ca shapelayer

I am trying to add gradient on ca shape layer its only giving gradient effect on current view frame if i am using it by adding masklayer it is not effecting on every layer seperately
here is my code:
CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor clearColor] CGColor];
gradientMask.strokeColor = [[UIColor blackColor] CGColor];
gradientMask.lineWidth = _borderStrokeWidth;
gradientMask.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
gradientMask.path = maskLayer.path;
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.8f],
[NSNumber numberWithFloat:1.0f],
nil];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(1.0,0.5);
gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
NSArray *colors = [NSArray arrayWithObjects:(id)[UIColor redColor].CGColor, (id)[UIColor greenColor].CGColor,(id)[UIColor blueColor].CGColor,(id)[UIColor yellowColor].CGColor, nil];
gradientLayer.colors = colors;
[gradientLayer setMask:gradientMask];
// [gradientLayer setMask:shapeLayer];
[self.layer addSublayer:gradientLayer];
kindly give suggestions

Making a gradient arc?

i wanna make an arc with the use of CAGradientLayer in such a way:-
20% of the arc have same single color then other 80% of arc has a gradient of two colors.
I already tried by hand on locations
startPoint endPoint property of CAGradientLayer but couldn't get the success and already go through from tutorials but somehow couldn't understand the concept properly.please solve my problem with clear description of it.
// for beizier path
- (UIBezierPath *)samplePath
{
UIBezierPath *path = [UIBezierPath bezierPath];
path = [UIBezierPath bezierPath];
[path addArcWithCenter:CGPointMake(200, 200) radius:30.0f startAngle:(3*M_PI)/4 endAngle:M_PI/4 clockwise:YES];
path.lineWidth = 30;
[[UIColor redColor] setStroke];
// [[UIColor colorWithRed:arc4random() green:arc4random() blue:arc4random() alpha:1.0] setFill];
[path stroke];
return path;
}
- (void)startAnimation
{
CAShapeLayer *shapeLayer;
if (self.pathLayer == nil)
{
shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [[self samplePath] CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.fillColor = nil;
shapeLayer.lineWidth = 30;
self.pathLayer = shapeLayer;
}
[self animationBasic];
[self gradientLayer:shapeLayer];
}
-(void)animationBasic
{
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 3.0;
pathAnimation.fromValue = #(0.0f);
pathAnimation.toValue = #(1.0f);
[self.pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
}
-(void)gradientLayer:(CAShapeLayer *)shapelayer
{
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.frame;
gradientLayer.colors = #[(__bridge id)[UIColor yellowColor].CGColor,(__bridge id)[UIColor redColor].CGColor ];
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.5f],
[NSNumber numberWithFloat:1.0f],
nil];
// gradientLayer.startPoint = CGPointMake(0,1);
// gradientLayer.endPoint = CGPointMake(1,1);
[self.layer addSublayer:gradientLayer];
gradientLayer.mask = shapelayer;
}
The locations property of a CAGradientLayer instance should be populated with the starting points (I know, the word stops makes it sound the opposite) of each color as specified in the colors property, from 0 to 1. These stops are rendered vertically from top to bottom.
So, this should work:
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.5f],
nil];
Now, at the same time, if you want to make the gradient horizontal (or any other direction), you can make use of the startPoint and endPoint properties.
gradientLayer.startPoint = CGPointMake(0.0, 0.5); //Default is (0.5, 0,0)
gradientLayer.endPoint = CGPointMake(1.0, 0.5); //Default is (0.5, 1.0)
//The gradientLayer will be rendered horizontally.
The startingPoint and endingPoint properties determine the direction and layout of the gradient in the layer. These are defined in the unit coordinate system, where each point is defined as a set of unit coordinates and the top left corner being the origin. So, (0,0) corresponds to the origin, (1,1) corresponds to the bottom right corner. You can check this excellent answer for a better explanation.
So to summarize, the gradient is rendered in the direction and region as specified by the startPoint and endPoint properties, with the colors rendered in the ratio specified in the locations property.
At the end, you can only understand this fully by tinkering with the properties and using various combinations to see what effect is rendered.

CAGradientLayer behind self.layer appearing above

I'm trying to make a custom UIButton class, except, when drawing the background of the button, and adding it as a sublayer using insertSubLayer behind: method, it still appears infront of the UIButton Textlabel.
My code is posted below, Any help would be greatly appreciated.
CALayer *layer = self.layer;
layer.cornerRadius = 3.0f;
layer.masksToBounds = YES;
layer.borderWidth = 1.0f;
layer.borderColor = [UIColor colorWithWhite:0.5f alpha:0.5f].CGColor;
self.titleLabel.textColor = [UIColor greenColor];
//layer.backgroundColor = [UIColor greenColor].CGColor;
bgColor = [CAGradientLayer layer];
bgColor.frame = self.layer.bounds;
self.backgroundColor = [UIColor colorWithWhite:1 alpha:1];
bgColor.colors = [NSArray arrayWithObjects:
(id)[UIColor colorWithWhite:0.97f alpha:1].CGColor,
(id)[UIColor colorWithWhite:0.87f alpha:1].CGColor,
nil];
bgColor.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:1],
nil];
[self.layer addSublayer:bgColor];
[self.layer insertSublayer:bgColor below:layer];
self.layer and layer in your code point to the same object. You're asking the layer to insert a sublayer behind itself - this is not possible. Sublayers are contained within the parent layer. Try
[self.layer insertSublayer:bgColor atIndex:0];
Instead of
[self.layer addSublayer:bgColor];
[self.layer insertSublayer:bgColor below:layer];
This will add the gradient at the lowest possible point in the layer hierarchy of your button.

adding gradient to UIView in drawRect

I am trying to add a CAGradientLayer in my drawRect, the code is the following:
- (void)drawRect:(CGRect)rect {
CAGradientLayer *gradientOverlay = [CAGradientLayer layer];
CGColorRef grayColor = [UIColor colorWithRed:37/255.f green:37/255.f
blue:37/255.f alpha:1.0].CGColor;
CGColorRef blueColor = [UIColor colorWithRed:23.0/255.0 green:171.0/255.0
blue:219.0/255.0 alpha:1.0].CGColor;
gradientOverlay.colors = [NSArray arrayWithObjects:
(id) grayColor,
(id) grayColor,
(id) blueColor,
nil];
gradientOverlay.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:0.4],
[NSNumber numberWithFloat:1],
nil];
CGPoint startPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMidY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMidY(rect));
gradientOverlay.startPoint = startPoint;
gradientOverlay.frame = self.bounds;
gradientOverlay.endPoint = endPoint;
self.layer.mask = gradientOverlay;
}
Any idea why this is not working?
How about trying this instead of overriding drawRect?
+ (void) applyGradient:(NSArray *)cgColors toView:(UIView *)view {
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = cgColors;
for(CALayer *layer in view.layer.sublayers) {
if([layer isKindOfClass:[CAGradientLayer class]]) return;
}
[view.layer insertSublayer:gradient atIndex:0];
}
Add your CAGradientLayer as a sublayer of your self.layer.
Note: If you're doing it in the drawRect: method make sure you're not adding a new CAGradientLayer every time drawRect: is called.
UPDATE (regarding the comment):
Here's the code for what you're asking:
//Create a layer that holds your background image and add it as sublayer of your self.layer
CALayer *layer = [CALayer layer];
layer.frame = self.layer.frame;
layer.contents = (id)[UIImage imageNamed:#"background.png"].CGImage;
[self.layer addSublayer:layer];
//Create your CAGradientLayer
CAGradientLayer *gradientOverlay = [CAGradientLayer layer];
CGColorRef grayColor = [UIColor colorWithRed:37/255.f green:37/255.f
blue:37/255.f alpha:1.0].CGColor;
CGColorRef blueColor = [UIColor colorWithRed:23.0/255.0 green:171.0/255.0
blue:219.0/255.0 alpha:1.0].CGColor;
gradientOverlay.colors = [NSArray arrayWithObjects:
(id) grayColor,
(id) grayColor,
(id) blueColor,
nil];
gradientOverlay.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:0.4],
[NSNumber numberWithFloat:1],
nil];
CGPoint startPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMidY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMidY(rect));
gradientOverlay.startPoint = startPoint;
gradientOverlay.frame = self.layer.frame;
gradientOverlay.endPoint = endPoint;
//set its opacity from 0 ~ 1
gradientOverlay.opacity = 0.6f;
//add it as sublayer of self.layer (it will be over the layer with the background image
[self.layer addSublayer:gradientOverlay];
Note: You don't have to do this in drawRect: method. Create your layer hierarchy in the init method for example, if you need to change the geometry of some views/layers override the layoutSubviews method.
Generally, you should only override drawRect: when you will be drawing your view using CoreGraphics.
A better place to put your code would be in init if you're creating this view in code, or awakeFromNib if you're placing this view in a .xib

Draw shadow on top of UITableViewCell

How can I draw a shadow on the top of a UITableViewCell? Tweetbot does this, here's a screenshot:
You could use a CAGradientLayer. In your cellForRowAtIndexPath, when creating a cell, create a gradient layer and add it to your cell. Note, you'll have to import the QuartzCore framework. Like so,
//top shadow
UIView *topShadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 10)];
CAGradientLayer *topShadow = [CAGradientLayer layer];
topShadow.frame = CGRectMake(0, 0, self.tableView.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];
[cell.contentView addSubview:topShadowView];