iOS: Mask a UIImage using UIBezierPath - iphone

I am trying to mask an image so that I can give it only two rounded corners. With the code that I have it just adds the mask in white over the image, but doesn't seem to apply it. What do I need to do different to mask the image corners?
CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:maskLayer.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(16.f, 16.f)];
maskLayer.fillColor = [[UIColor whiteColor] CGColor];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [roundedPath CGPath];
// Add mask
self.imageView.layer.mask = maskLayer;

Round two corners in UIView
As mentioned in the above linked question, you probably need to remove the view from the heirarchy before applying its mask.
[self.imageView removeFromSuperview];
self.imageView.layer.mask = maskLayer;
[self.view addSubview:self.imageView];
Also, your maskLayer has no bounds. You need to set it to the frame (or bounds) of the view you're trying to mask.
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.imageView.frame;

Related

Master-Details SplitViewController Custom UINavigationBar

I have a Master-Details project setup and running in XCode with no problems at all and everything works fine. However, when I attempt to round the top right and left corners of the NavigationBar it has a very strange effect. It basically, offsets the 'touch' response of the 'back' left button on the details view.
The button still works, but it seems that the iPhone can only pick up the user's touch when they click just below the NavigationBar and not the button itself.
The code I have is:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor darkGrayColor];
UIImage *img = [UIImage imageNamed:#"nav-bar"];
[img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.tintColor = color;
// Create mask to round corners
CGRect bounds = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
// Apply mask to navigation bar
[self.layer addSublayer:maskLayer];
self.layer.mask = maskLayer;
// Apply logo to navigation bar
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo"]];
self.topItem.titleView = imageView;
}
Here is a screen shot of what I mean, button only responses when I touch where the arrow is pointing:
--- UPDATE ---
After some testing I've worked out the problem is with the 'self.layer.mask = maskLayer' line. I have refactored the code and tested in another project that just uses xib files and not story boards, and dont have any problems, but its still not working in the current project.
CGRect bounds = CGRectMake(0, 0, navigationController.navigationBar.bounds.size.width,
navigationController.navigationBar.bounds.size.height);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
// Apply mask to navigation bar
//navigationController.navigationBar.layer.mask = maskLayer;
[navigationController.navigationBar.layer addSublayer:maskLayer];
navigationController.navigationBar.layer.mask = maskLayer;
use self.bounds instead of self.frame. You probably want to draw relatively to your own coordinates system and not relatively to your own parent view.

CAShapeLayer isn't rounding corners and stroke isn't on top

Hi guys I've creates this box, basically the corner radius isn't working & the stroke doesn't show on the top side of the shape either. Is there anyway to get this working?
UIBezierPath* conPath = [UIBezierPath bezierPath];
[conPath moveToPoint:CGPointMake(conX, conY)];
[conPath addLineToPoint:CGPointMake(conX, conY+50)];
[conPath addLineToPoint:CGPointMake(conX+220, conY+50)];
[conPath addLineToPoint:CGPointMake(conX+220, conY)];
CAShapeLayer* conLayer = [CAShapeLayer layer];
conLayer.path = conPath.CGPath;
conLayer.cornerRadius = 5.0;
UIColor *bg = [UIColor colorWithWhite:1 alpha:0.7];
[conLayer setFillColor:bg.CGColor];
[conLayer setStrokeColor:[UIColor grayColor].CGColor];
[[self layer] addSublayer:conLayer];

rounded corners on UIPageViewController

I was wondering if anyone was ever successful in changing the corners of an UIPageViewController (the fancy book turning animation of iBooks) to rounded corners?
I tried this but to no avail:
[self.notebookPages setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.notebookPages.dataSource = self.pageModelController;
self.notebookPages.doubleSided = NO;
[self addChildViewController:self.notebookPages];
// mask
CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 332, 480)
byRoundingCorners:UIRectCornerTopRight | UIRectCornerBottomRight
cornerRadii:CGSizeMake(15.f, 15.f)];
maskLayer.fillColor = [[UIColor whiteColor] CGColor];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [roundedPath CGPath];
self.notebookPages.view.layer.mask = maskLayer;
[self.notebookScrollNavigationController.notebook.pages addSubview:self.notebookPages.view];
self.notebookPages.view.frame = CGRectMake(0, 0, 332, 480);
[self.notebookPages didMoveToParentViewController:self];
This is all a bit hardcoded (which is obviously bad) but I was just trying to find out if rounded corners would work. However, I only get a non-rounded transparent corner:
Add this import:
#import <QuartzCore/QuartzCore.h>
Now you can use cornerRadius:
self.notebookPages.view.layer.cornerRadius = 6;

Is it possible to add a background Image to a CAShape? (iPhone)

I am trying to distort an image in an arbitrary way, following for example a bezier shape. I have used CAShapeLayer to create the shape, but then it seems that setting its contents to an Image does not work. How can I have the image distorted following that shape? Is it even possible?
Thank you!
it is not possible to do so, but i succeeded in doing so by putting a CALayer on top a CAShapeLayer.
this is my code:
CALayer *image =[CALayer layer];
image.frame = CGRectMake(0, 0, 75, 75);
image.contents = (id) [UIImage imageNamed:#"number-1"].CGImage;
[self.layer addSublayer:image];
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 75, 75)];
blueCircleLayer = [CAShapeLayer layer];
blueCircleLayer.path = circle.CGPath;
blueCircleLayer.strokeColor = [UIColor blueColor].CGColor;
blueCircleLayer.fillColor = [UIColor clearColor].CGColor;
blueCircleLayer.shadowColor =[UIColor blackColor].CGColor;
blueCircleLayer.shadowOffset = CGSizeMake(0.0f, 5.0f);
blueCircleLayer.shadowOpacity = 0.7f;
blueCircleLayer.lineWidth = 7.0;
[self.layer addSublayer:blueCircleLayer];
This is currently not possible. I would suggest filing a radar (http://bugreport.apple.com) if you think this should be supported.
See also: Can a CGImage be added to the contents property of a CAShapeLayer?

UINavigationBar Rounded Two Corners

I want to round the top right and top left of the UINavigationBar.
I know that there are functions for changing the views corner radius, but is it possible to do something similar to the standard UINavigationBar?
If you don't know what I'm talking about, check out this:
Thanks!
the following code works for me (tested on iOS5).
The following code rounds the top left/right corners of the main navigation bar. Additionally, it adds a shadow to it:
CALayer *capa = [self.navigationController navigationBar].layer;
[capa setShadowColor: [[UIColor blackColor] CGColor]];
[capa setShadowOpacity:0.85f];
[capa setShadowOffset: CGSizeMake(0.0f, 1.5f)];
[capa setShadowRadius:2.0f];
[capa setShouldRasterize:YES];
//Round
CGRect bounds = capa.bounds;
bounds.size.height += 10.0f; //I'm reserving enough room for the shadow
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
[capa addSublayer:maskLayer];
capa.mask = maskLayer;
The best way is to override drawRect in UINavigationBar and use a custom image.
You might find this helpful. Maybe you could also do some kind of masking with CoreAnim/Image? I'm not very knowledgeable about the Core* family...
http://foobarpig.com/iphone/uinavigationbar-with-solid-color-or-image-background.html