I used the following method to get rounded corners on a view in my application:
(objective-c:)
hoursTable.layer.cornerRadius = 5.0;
[hoursTable setClipsToBounds:YES];
(my actual code is in rubymotion:)
self.view.layer.cornerRadius = 10
self.view.layer.masksToBounds = true
Now all the corners of that view are rounded with 10pt, how do I only apply the effect on the top-left and top-right corners and leave the bottom left and bottom right corner squared?
I have the category on UIView with this code:
- (void)setRoundedCorners:(UIRectCorner)corners radius:(CGSize)size {
UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:size];
CAShapeLayer* maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
self.layer.mask = maskLayer;
[maskLayer release];
}
Remove the last line if you use ARC.
Example of usage:
[hoursTable setRoundedCorners:UIRectCornerTopLeft|UIRectCornerTopRight radius:CGSizeMake(5.0, 5.0)];
Try to create path manually
CAShapeLayer* shape = [CAShapeLayer layer];
CGMutablePathRef path = CGPathCreateMutable();
/*...*/
CGPathMoveToPoint(path, NULL, 0, 0);
/*create path for view*/
shape.path = path;
CGPathRelease(path);
view.layer.mask = shape;
Related
UIButton corners only two sides i.e. top right and bottom right with following:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_nearmeButton.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerBottomLeft) cornerRadii:CGSizeMake(20.0, 20.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.view.bounds;
maskLayer.path = maskPath.CGPath;
_nearmeButton.layer.mask = maskLayer;
But how to give border colour to above UIButton same as given image .
You are on the right track. Instead of setting your path as a mask you can add it to the buttons layer. Basically (more or less) every UIView is backed by a CALayer. Just set the colors you want on the stroke and the fill and add it to the buttons layer, and you are done.
UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:_nearmeButton.bounds byRoundingCorners:(UIRectCornerTopRight | UIRectCornerBottomRight) cornerRadii:CGSizeMake(20.0, 20.0)];
CAShapeLayer *borderLayer = [[CAShapeLayer alloc] init];
borderLayer.frame = self.view.bounds;
borderLayer.path = borderPath.CGPath;
borderLayer.strokeColor = [UIColor redColor].CGColor;
borderLayer.fillColor = [UIColor clearColor].CGColor;
borderLayer.lineWidth = 1.0;
[_nearmeButton.layer addSublayer:borderLayer];
If your buttons size changes you need to update the layer size also.
I just updated to Xcode 8 and I had problem with Blur (UIVisualEffectView) on iOS 10, but I solve it. But after I fixed the blur layer mask second problem is appears, when I getting the reference of maskView from UIVisualEffectView and apply the new UIBezierPath nothing happens.
Code example:
-(void)prepareEffectView{
//Frame
CGRect frame = self.view.bounds;
UIView *maskView = [[UIView alloc] initWithFrame:frame];
maskView.backgroundColor = [UIColor blackColor];
maskView.layer.mask = ({ // This mask draws a rectangle and crops a circle inside it.
UIBezierPath *maskLayerPath = [UIBezierPath bezierPath];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithRect:frame]];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(self.btnScan.center.x, self.btnScan.center.y, 0, 0)]];
[maskLayer setPath:maskLayerPath.CGPath];
[maskLayerPath setUsesEvenOddFillRule:YES];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = maskLayerPath.CGPath;
mask.fillRule = kCAFillRuleEvenOdd;
mask;
});
self.visualEffectView.maskView = maskView;
}
-(void)openAperture{
//Blur layer
CGRect frame = self.view.bounds;
CAShapeLayer *maskLayer = (CAShapeLayer *)self.visualEffectView.maskView.layer.mask;
//New path value
UIBezierPath *maskLayerPath = [UIBezierPath bezierPath];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithRect:frame]];
[maskLayerPath appendPath:[UIBezierPath bezierPathWithRoundedRect:UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(58, 15, 66, 15)) cornerRadius:1]];
[maskLayer setPath:maskLayerPath.CGPath];
//Animation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"path"];
animation.delegate = self;
animation.duration = 0.44;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fromValue = (id)maskLayer.path;
animation.toValue = (id)maskLayerPath.CGPath;
[maskLayer addAnimation:animation forKey:#"animatePath"];
}
Apple Note About VisualEffectView issue on iOS 10
Transitions are tough in this realm, as maskView is the only way to
ensure that the effect works, but maskView also isn't animatable.
https://forums.developer.apple.com/message/184810#184810
The only the way to use "CAShapeLayer" as a mask is to apply your shape to UIView.layer.mask and then put it to UIVisualEffectView.maskView.
The maskView of UIVisualEffectView isn't animatable.
I have the same problem.
I tried to do next: (Swift code)
visualEffectView.layer.mask = maskView.layer.mask
instead of visualEffectView.mask = maskView
If so, path animation works fine, but then blur effect is gone.
If you find a solution, please update the post.
I have the following code which makes an oval rotating around its center. I would like to be able to position it within UIImageView at a certain position (say a middle of the view).
I would really appreciate if someone could help me out on this one.
-(void)drawCircle
{
CGMutablePathRef circlePath = CGPathCreateMutable();
int radius = 400;
CGRect circleRect = CGRectMake(CENTER_Y-radius*0.7, CENTER_X-radius, 1.4*radius, 2*radius);
float midX = CGRectGetMidX(circleRect);
float midY = CGRectGetMidY(circleRect);
CGAffineTransform transform = CGAffineTransformMakeTranslation(-midX, -midY);
CGPathAddEllipseInRect( circlePath ,&transform , circleRect);
CAShapeLayer *circle = [[CAShapeLayer alloc] init];
circle.path = circlePath;
circle.opacity = 0.1;
circle.contentsScale = SCREEN_SCALE;
circle.fillColor = [UIColor blueColor].CGColor;
[aView.layer addSublayer:circle];
CABasicAnimation* theAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
theAnimation.fromValue = 0;
theAnimation.toValue = #(2*M_PI);
theAnimation.duration=3.5;
theAnimation.autoreverses=FALSE;
theAnimation.repeatCount=HUGE_VALF;
theAnimation.fillMode = kCAFillModeBoth;
theAnimation.removedOnCompletion=FALSE;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circle addAnimation:theAnimation forKey:#"transform.rotation.z"];
}
a missing piece:
[circle setPosition:CGPointMake(CENTER_X, CENTER_Y)];
I have to round only upper corners of UIView. I'm trying to use the following code:
UIBezierPath *maskEmailPath = [UIBezierPath bezierPathWithRoundedRect:self.emailandAccessView.bounds byRoundingCorners:UIRectCornerBottomLeft cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskEmailLayer = [CAShapeLayer layer];
maskEmailLayer.frame = self.myview.bounds;
maskEmailLayer.path = maskEmailPath.CGPath;
self.myview.layer.mask = maskEmailLayer;
but it hides everything in that view. Can anyone please help me.
This is how you do it.
CALayer *capa = self.view.layer;
CGRect bounds = capa.bounds;
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(5.0, 5.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
[capa addSublayer:maskLayer];
capa.mask = maskLayer;
Hi! I want to draw a rounded corner of my UIView. Only one, others cannot be changed.
Starting in iOS 3.2, you can use the functionality of UIBezierPaths to create an out-of-the-box rounded rect (where only corners you specify are rounded). You can then use this as the path of a CAShapeLayer, and use this as a mask for your view's layer:
// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds
byRoundingCorners:UIRectCornerTopLeft
cornerRadii:CGSizeMake(10.0, 10.0)];
// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;
// Set the newly created shape layer as the mask for the image view's layer
imageView.layer.mask = maskLayer;
And that's it - no messing around manually defining shapes in Core Graphics, no creating masking images in Photoshop. The layer doesn't even need invalidating. Applying the rounded corner or changing to a new corner is as simple as defining a new UIBezierPath and using its CGPath as the mask layer's path. The corners parameter of the bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: method is a bitmask, and so multiple corners can be rounded by ORing them together.
NOTE - Layer masks will not render when used in combination with the CALayer renderInContext method. If you need to use this try rounding corners with the following: Just two rounded corners?.
I made a method of StuDev's answer:
+ (CAShapeLayer *) roundedCornerOnImage: (UIImageView *)imageView onCorner: (UIRectCorner)rectCorner
{
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds
byRoundingCorners:rectCorner
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;
return maskLayer;
}
Example of usage on a imageview in a UITableViewCell:
if (indexPath.row == 0)
cell.imageView.layer.mask = [Helper roundedCornerOnImage:cell.imageView onCorner:UIRectCornerTopLeft];
else if (indexPath.row == self.arrayPeople.count - 1)
cell.imageView.layer.mask = [Helper roundedCornerOnImage:cell.imageView onCorner:UIRectCornerBottomLeft];
Thanks to StuDev for a great solution!
+ (CAShapeLayer *) roundedCornerOnImage: (UIImageView *)imageView onCorner: (UIRectCorner)rectCorner
{
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds
byRoundingCorners:rectCorner
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;
imageView.layer.mask=maskLayer
return maskLayer;
}
if (indexPath.row == 0)
[Helper roundedCornerOnImage:cell.imageView onCorner:UIRectCornerTopLeft];
else if (indexPath.row == self.arrayPeople.count - 1)
[Helper roundedCornerOnImage:cell.imageView onCorner:UIRectCornerBottomLeft];
An updated answer to above , you dont need to return and manage that. It can be done in that function.
I have made a function for make the Custom corner radius after doing some small R&D as following:
+(void)setConerRadiusForTopLeft:(BOOL)isForTopLeft ForTopRight:(BOOL)isForTopRight ForBottomLeft:(BOOL)isForBottomLeft ForBottomRight:(BOOL)isForBottomRight withCornerRadius:(float)cornerRadius forView:(UIView *)view
{
UIRectCorner corners = (isForTopLeft ? UIRectCornerTopLeft : 0) |
(isForTopRight ? UIRectCornerTopRight : 0) |
(isForBottomLeft ? UIRectCornerBottomLeft : 0) |
(isForBottomRight ? UIRectCornerBottomRight : 0);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = view.bounds;
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;
}