Move a CALayer frame but not the clip mask - ios

I would like the move a layer by setting its frame, but without the layer clip being moved as well.
I have created a layer which is created as follows:
layer = [CustomLayer layer];
layer.frame = CGRectMake(50, 50, 100, 30);
[layer setNeedsDisplay];
[self.view.layer addSublayer:layer];
And a clip layer like so:
clipLayer = [CAShapeLayer layer];
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRoundedRect:layer.bounds
cornerRadius:10.0f];
clipLayer.path = clipPath.CGPath;
layer.mask = clipLayer;
However, at some later point in my code, if I set the layer frame:
layer.frame = CGRectOffset(layer.frame, -20.0, 0.0);
Both the layer and its clip mask are offset. The effect I am trying to achieve is to 'scroll' a layer beneath a rounded rectangular clipping area. Any ideas?

I would clip the clip layer to a third layer.This third layer needs to:
be of the same size of the layer you want to mask
be at the same position of the layer you want to mask
have clearColor background color
then just move the underlying layer and third layer with its clipped layer will stay put.
NOTE: This worked for me - although, you also have to ensure that the layer being moved is a subview of the clipping layer.

Related

How to remove black edge on UIImageView with rounded corners and a border width?

I have the following code to make the UIImageView in each of my UITableView's cells have rounded corners:
- (void)awakeFromNib
{
// Rounded corners.
[[cellImage layer] setCornerRadius:([cellImage frame].size.height / 2)];
[[cellImage layer] setMasksToBounds:YES];
[[cellImage layer] setBorderColor:[[UIColor whiteColor] CGColor]];
[[cellImage layer] setBorderWidth:3]; // Trouble!
}
I want the images to have a bit of a gap between them, and figured I could make use of the border width to make that happen. Below is an image of what actually happened:
It's that faint black border that I want to know how to get rid of. I'd like to think there's a way of doing it using border width. If not, the best approach might be just to resize the image itself and just set the border width to be 0.
Rather than using corner radius, you can create bezier path for the mask, create a shape layer for that path, and then specify that shape layer for the image view's layer's mask:
CGFloat margin = 3.0;
CGRect rect = CGRectInset(imageView.bounds, margin, margin);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(imageView.bounds.size.width/2, imageView.bounds.size.height/2) radius:radius startAngle:0 endAngle:M_PI*2 clockwise:NO];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = path.CGPath;
imageView.layer.mask = mask;
What you are doing is, you are clipping the profile image and the border together, which is making the cell's profile image extending through the border.
You are missing this line:-
cellImage.clipsToBounds = YES;

how to draw oval shape in UIImageview

I want to draw a UIImageView in oval shape. i try to draw but i cloud not find answer. i show most of round or circle shape.
enter link description here
i try this but this is not work
#import <QuartzCore/QuartzCore.h>`
CALayer *imageLayer = YourImageview.layer;
[imageLayer setCornerRadius:5];
[imageLayer setBorderWidth:1];
[imageLayer setMasksToBounds:YES];
If you want to draw an imageview in an oval shape, follow below steps:
Create a UIBezierPath using bezierPathWithOvalInRect
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:YOUR_RECT];
Create a mask layer by using CAShapeLayer
CAShapeLayer *maskLayer = [CAShapeLayer layer];
Now set the bezier path as mask layer's path
maskLayer.path = path.CGPath;
Then we are going mask our view with our own mask layer.
YourImageview.layer.mask = maskLayer;
That's all. Try it.
Yes, you can done it by draw BezierPath but even we can't get exact round-rect image...
so i'll give you other trick...
you use 2 imageview
one for main-imageview in which you pass your image..
second(overhead imageviw) for round or circle shape image with orange color border which is transparent in middle/center.
when you use overheadimageview over main imageview then you can find exact round or circle shape image
You need to have a corner Radius half of what your image size is, to draw the cricular.
But to draw oval shape you need smaller radius.
CGFloat imgSize = 55;
UIImageView *imgViewProfile = [[UIImageView alloc] init];
imgViewProfile.frame = CGRectMake(5, 5, imgSize, imgSize);
imgViewProfile.layer.cornerRadius = imgSize / 2;
imgViewProfile.clipsToBounds = YES;
imgViewProfile.contentMode = UIViewContentModeScaleAspectFill;
[view addSubview:imgViewProfile];

Animate the mask of a mask of a CALayer

Goal:
I am drawing a custom shape that has a gradient. I also want to animate the drawing of this shape by having it draw in from left to right.
Problem:
The code below works on an iPad simulator, but it doesn't work on my iPad 4 running iOS 7. Does anyone know how to make this work on the device? Is there a different way to achieve this same result?
Explanation of my Code:
My code works (only on simulator) using 3 CALayers.
gradientLayer holds my gradient.
shapeMaskLayer holds my custom shape.
animationMaskLayer animates it's path to simulate drawing from left to right
animationMaskLayer --masks--> shapeMaskLayer --masks--> gradientLayer
I then animate the frame of animationMaskLayer to animate the whole shape.
Code:
// Animation Mask Rects
CGPathRef leftStartingRectPath = CGPathCreateWithRect(CGRectMake(0, 0, 0, self.frame.size.height), 0);
CGPathRef fullViewRectPath = CGPathCreateWithRect(CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), 0);
// Animation Mask Layer
CAShapeLayer *animationMaskLayer = [CAShapeLayer layer];
animationMaskLayer.path = fullViewRectPath;
animationMaskLayer.fillColor = UIColor.blackColor.CGColor;
// Shape Mask Layer
CAShapeLayer *shapeMaskLayer = [CAShapeLayer layer];
shapeMaskLayer.path = CGPathCreateWithEllipseInRect(self.bounds, 0);
shapeMaskLayer.fillColor = [UIColor blueColor].CGColor;
shapeMaskLayer.mask = animationMaskLayer;
// Gradient Layer
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.bounds;
gradientLayer.colors = self.colors;
gradientLayer.mask = shapeMaskLayer;
mountainLayer.anchorPoint = pt(0, 0);
mountainLayer.position = pt(0, 0);
[self.layer addSublayer:gradientLayer];
// Left To Right Animation
CABasicAnimation *leftToRightAnimation = [CABasicAnimation animationWithKeyPath:#"path"];
leftToRightAnimation.duration = 0.5;
leftToRightAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
leftToRightAnimation.fromValue = (__bridge id)leftStartingRectPath;
leftToRightAnimation.toValue = (__bridge id)fullViewRectPath;
leftToRightAnimation.fillMode = kCAFillModeForwards;
leftToRightAnimation.removedOnCompletion = NO;
[animationMaskLayer addAnimation:leftToRightAnimation forKey:#"animatePath"];
// Memory Management
CGPathRelease(leftStartingRectPath);
CGPathRelease(fullViewRectPath);
Animating the mask of a mask? I'm surprised that even works in the simulator.
Have you tried nesting two layers, with the parent layer with masksToBounds on? You can then set an independent mask on both layers, and the outer layer will effectively mask your inner layer with its own mask (due to masksToBounds). It probably doesn't matter which layer gets which mask (because you want the intersection of both masks).
With the code you listed in your question, you would just need to add one line, and comment out one line to get the correct functionality:
self.layer.mask = animationMaskLayer;
// shapeMaskLayer.mask = animationMaskLayer;

Keeping CAShapeLayer Mask Static During Animation

I'm trying to rotate a UIImageView within a circular mask (which is set with myImageView.layer.mask). The problem is that any time I attempt to rotate said UIImageView, the mask rotates with it. Here is some code.
Setting up the mask:
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, - 169)
radius:191
startAngle:0.0
endAngle:2*M_PI
clockwise:YES];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setFrame:myImageView.bounds];
[shapeLayer setPath:[path CGPath]];
myImageView.layer.mask = shapeLayer;
Animation:
[UIView animateWithDuration:kRotationTime animations:^(void){
myImageView.transform = CGAffineTransformMakeRotation(angle);
}];
And that's basically all there is to it. A UIImageView rotating about its own center within a fixed-position circular mask--that's the desired effect. Perhaps there is another way to structure the view hierarchy so that myImageView and the mask are siblings, but I haven't had luck going that route.
Put the image view into an additional plain UIView superview. Set the layer mask on the superview. Animate the image view.

Is there a way to prevent CALayer shadows from overlapping adjacent layers?

I have a collection of CALayers. Each layer is a sublayer of the same parent CALayer, and each has a shadow applied to it. The layers are positioned dynamically, and there are many of them, so I can't predict how they'll be arranged ahead of time.
If the layers are adjacent to each other (close enough that they are almost touching) the shadow of one of the CALayers is rendered on top of the other CALayer. That's probably the desired effect in most cases, but I want my layers to exist in the same z-plane. (An example of this is the way CSS3 shadows are applied to block elements in web design.)
Is this possible? How can I achieve this?
(I had this idea: Adding a 'shadow' sublayer to each CALayer with my own shadow image, and setting the z-position to a lower value. But doesn't the layer-tree make this impossible? Z-positions in one layer's coordinate system are independent from z-positions in another layer's coordinate system, right?)
If all of the shadowed layers have the same shadow settings, put them into a container layer and set the shadow on the container layer. Example:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *containerLayer = [CALayer layer];
containerLayer.frame = self.view.bounds;
containerLayer.shadowRadius = 10;
containerLayer.shadowOpacity = 1;
[self.view.layer addSublayer:containerLayer];
CAShapeLayer *layer1 = [CAShapeLayer layer];
layer1.bounds = CGRectMake(0, 0, 200, 200);
layer1.position = CGPointMake(130, 130);
layer1.path = [UIBezierPath bezierPathWithOvalInRect:layer1.bounds].CGPath;
layer1.fillColor = [UIColor redColor].CGColor;
[containerLayer addSublayer:layer1];
CAShapeLayer *layer2 = [CAShapeLayer layer];
layer2.bounds = CGRectMake(0, 0, 200, 200);
layer2.position = CGPointMake(170, 200);
layer2.path = [UIBezierPath bezierPathWithOvalInRect:layer2.bounds].CGPath;
layer2.fillColor = [UIColor blueColor].CGColor;
[containerLayer addSublayer:layer2];
}
Output:

Resources