Why can't I add a mask to UITableViewCell's contentView? - iphone

Is this not possible?
I've tried this:
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, 200, 30) byRoundingCorners:(UIRectCornerTopRight | UIRectCornerTopLeft) cornerRadii:CGSizeMake(8.0, 8.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
maskLayer.fillColor = [UIColor blackColor].CGColor;
self.contentView.layer.mask = maskLayer;
self.contentView.layer.masksToBounds = YES;
and nothing happens. However, if do the same thing upon another view in the contentView, the mask works as expected. What gives?

It worked for me if I took the "contentView" out of your last two lines of code. I don't know why that works, maybe you can't mask the content view?

Related

How to hide a subframe of a UIView?

lets say i have a UIImageView with a frame (0,0,100,30)
.that imageView was assigned an image.
whats the simplest way to show only part of the image?
for example: only what appears in points 30-60 (width) and 0-30 (height). that means that the left and right edges of the image should be hidden.
just to clarify, i don't want to move the view nor change it's size, i just want to hide a subrect of it's frame.
You could always set a mask.
CALayer *maskLayer = [CALayer layer];
maskLayer.backgroundColor = [UIColor blackColor].CGColor;
maskLayer.frame = CGRectmake(30.0, 0.0, 30.0, 30.0);
view.layer.mask = maskLayer;
Masks can be any type of layer, so you could even use a CAShapeLayer for complex masks and do some really cool stuff.
i've found this solution works for me, https://stackoverflow.com/a/39917334/3192115
func mask(withRect rect: CGRect, inverse: Bool = false) {
let path = UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.view.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
imageView?.layer.mask = maskLayer
}
I believe masking the image is the best option. But if you were to rotate, transform, animate or want a clear background you can do something like this:
Create a sub view which is the size of the image you want to show. Make sure it has clipsToBounds to true and position the image accordingly.
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
//this is the part of the image you wish to see
UIView *imageWindow = [[UIView alloc] initWithFrame:CGRectMake(30, 0, 30, 30)];
imageWindow.clipsToBounds = YES;
//your image view is the height and width of mainView and x and y is imageWindow - mainView. You can do this manually or put in calculations.
UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake(imageWindow.frame.origin.x - mainView.frame.origin.x, imageWindow.frame.origin.y - mainView.frame.origin.y, mainView.frame.size.width, mainView.frame.size.height)];
myImage.image = [UIImage imageNamed:#"1024x1024.png"];
[imageWindow addSubview:myImage];
[mainView addSubview:imageWindow];
[self.view addSubview:mainView];
Looking over my code, I don't think mainView is necessary and you could add imageWindow to self.view directly.

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.

Set border around UIImageView

I want to apply two types of border on a UIImageView:
One is the border on the layer of the UIImageView.
Second is the border around the layer of the UIImageView.
How can I do this?
Try
#define kBorderWidth 3.0
#define kCornerRadius 8.0
CALayer *borderLayer = [CALayer layer];
CGRect borderFrame = CGRectMake(0, 0, (imageView.frame.size.width), (imageView.frame.size.height));
[borderLayer setBackgroundColor:[[UIColor clearColor] CGColor]];
[borderLayer setFrame:borderFrame];
[borderLayer setCornerRadius:kCornerRadius];
[borderLayer setBorderWidth:kBorderWidth];
[borderLayer setBorderColor:[[UIColor redColor] CGColor]];
[imageView.layer addSublayer:borderLayer];
And don't forget to import QuartzCore/QuartzCore.h
This example will draw a boarder on the layer, but change it's frame slightly to make the border around the layer.
Another way
You must import
#import <QuartzCore/QuartzCore.h>
Then add code for your UIImageView
imgView.clipsToBounds = YES;
imgView.layer.cornerRadius = 8.0;
imgView.layer.borderWidth = 2.0;
imgView.layer.borderColor = [UIColor greenColor].CGColor;
An other way is to add another layer that goes a bit outside of the UIImageView's layer like so :
CALayer * externalBorder = [CALayer layer];
externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2);
externalBorder.borderColor = [UIColor blackColor].CGColor;
externalBorder.borderWidth = 1.0;
[myView.layer addSublayer:externalBorder];
myView.layer.masksToBounds = NO;
Swift 5
Beware when using a UIImageView; masksToBounds = false means the image will spill over
let outsideBorder = CALayer()
outsideBorder.frame = CGRect(x: -1, y: -1, width: myView.frame.size.width+2, height: myView.frame.size.height+2)
outsideBorder.borderColor = UIColor.black.cgColor
outsideBorder.borderWidth = 1.0
myView.layer.addSublayer(outsideBorder)
myView.masksToBounds = false

iphone - How can I produce an imageview with both rounded corner and shadow?

something exactly like above?
I know how to produce a rounded corner:
imageView.layer.cornerRadius = 10;
imageView.layer.shouldRasterize = YES;
imageView.layer.masksToBounds = YES;
For the shadow, I have tried
imageView.layer.shadowOffset = CGSizeMake(1, 1);
imageView.layer.shadowRadius = 5;
imageView.layer.shadowOpacity = 0.4;
imageView.layer.shadowColor = [UIColor blackColor].CGColor;
imageView.layer.shouldRasterize = YES;
But imageView.layer.masksToBounds = YES; from rounded corner kills the shadow.
Another question is that how to produce a shadow exactly like shown in the image? I produced this image in photoshop, I used 120 degree as the direction of the light. But if I used the code above, and turn off maskToBounds, I can see the shadow and it is ugly.
Or can I produce a rounded corner+shadow image frame in photoshop and apply the frame to every image in my app? I think that will give better performance. shadowing and cornering the images on the fly will have terrible performance if all images are on a scroll.
Thanks
Try this :
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [UIColor blueColor].CGColor;
sublayer.shadowOffset = CGSizeMake(0, 3);
sublayer.shadowRadius = 5.0;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shadowOpacity = 0.8;
sublayer.frame = CGRectMake(30, 30, 128, 192);
sublayer.borderColor = [UIColor blackColor].CGColor;
sublayer.borderWidth = 2.0;
sublayer.cornerRadius = 10.0;
[self.view.layer addSublayer:sublayer];
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = sublayer.bounds;
imageLayer.cornerRadius = 10.0;
imageLayer.contents = (id) [UIImage imageNamed:#"BattleMapSplashScreen.jpg"].CGImage;
imageLayer.masksToBounds = YES;
[sublayer addSublayer:imageLayer];
And take look at the original source
I would use two image views. A background png that has the shadow (can be re-used for every image) and the foreground png image which has rounded corners.
You probably want to use a different layer for shadowing, and keep your masksToBounds and rounding code. In this example imageView is the name the image view that you want to shadow and round:
CALayer *shadowLayer = [[[CALayer alloc] init] autorelease];
sublayer.frame = imageView.bounds;
sublayer.masksToBounds = NO;
sublayer.shadowOffset = CGSizeMake(1, 1);
sublayer.shadowRadius = 5;
sublayer.shadowOpacity = 0.4;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shouldRasterize = YES;
[imageView.layer insertSublayer:shadowLayer atIndex:0]; // Put it underneath the image
That should give you the shadow. Now to avoid the slow recalculating, I suggest creating a UIImage out of the image. See this link: Create UIImage from shadowed view while retaining alpha?.
Hope this helps!

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?