Why UIBezierPath's corners are transparent? - ios

I want to make my TopLeft and TopRight corners with corner radius. It works with this code:
let rectShape = CAShapeLayer()
rectShape.bounds = self.name.frame
rectShape.position = self.name.center
rectShape.path = UIBezierPath(roundedRect: self.name.bounds, byRoundingCorners: .TopLeft | .TopRight, cornerRadii: CGSize(width: 20, height: 20)).CGPath
rectShape.backgroundColor = UIColor.blackColor().CGColor
self.name.layer.mask = rectShape
but it makes the corners transparent, like this:
How can I make them visible?

Bcs it's just a mask, your layer still square. There are many ways to do it, for example, you can paint your own layer and add it as sublayer. This properties should help you:
layer.fillColor = LAYER_COLOR.CGColor;
layer.strokeColor = LAYER_BORDER_COLOR.CGColor;
layer.lineWidth = LAYER_BORDER_WIDTH;
layer.opacity = LAYER_OPACITY;

Related

Issue with rounded corners of ImageView with gradient colour

I created a rectangle using following code and now I need to rounded the corners of this rectangle. I set layer.cornerRadius also, can anyone help me?
My code as below,
private func setGradientBorder(_ ivUser:UIImageView) {
ivUser.layer.masksToBounds = true
ivUser.layer.cornerRadius = ivUser.frame.width / 2
let gradient = CAGradientLayer()
gradient.frame = CGRect(origin: CGPoint.zero, size: ivUser.frame.size)
gradient.colors = [UIColor.blue.cgColor, UIColor.green.cgColor]
let maskPath = UIBezierPath(roundedRect: ivUser.bounds,
byRoundingCorners: [.allCorners],
cornerRadii: CGSize(width: ivUser.frame.width/2, height: ivUser.frame.height/2)).cgPath
let shape = CAShapeLayer()
shape.lineWidth = 2
shape.path = maskPath
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
gradient.mask = shape
ivUser.layer.addSublayer(gradient)
}
output: gradient does not display properly rounded
This is how UIBezierPath works. Half of the line width will go on one side of the actual path, and half will go on another. Thats why it looks kinda cut out.
You will need to inset your paths rect by half of the line width, something like this:
let lineWidth: CGFloat = 2
let maskPath = UIBezierPath(roundedRect: ivUser.bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2),
byRoundingCorners: [.allCorners],
cornerRadii: CGSize(width: ivUser.frame.width/2, height: ivUser.frame.height/2)).cgPath

Add a shadow with CAShapeLayer?

I have a CAShapeLayer with bottom rounded corners only. What I want is to add a shadow at the bottom, but it's not working, even though the code looks obviously right. All it does it round the bottom corners but I don't see a shadow.
let shapeLayer = CAShapeLayer()
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
shapeLayer.path = path
shapeLayer.shadowColor = UIColor(r: 233, g: 233, b: 233).cgColor
shapeLayer.shadowOffset = CGSize(width: 0.0, height: 2.8)
shapeLayer.shadowOpacity = 1.0
shapeLayer.shadowRadius = 0.0
shapeLayer.shouldRasterize = true
shapeLayer.rasterizationScale = UIScreen.main.scale
layer.rasterizationScale = UIScreen.main.scale
layer.mask = shapeLayer
The shapeLayer is rounding the corners of your view because it's set as the layer's mask. You probably want to add it as a sublayer instead.
Old:
layer.mask = shapeLayer
New:
layer.addSublayer(shapeLayer)
I wrote another answer about adding a shadow to a view with rounded corners here if it helps: https://stackoverflow.com/a/41475658/6658553
Another solution,
The following UIView extension will work with any shape you mask the view with
extension UIView {
func addShadow() {
self.backgroundColor = UIColor.clear
let roundedShapeLayer = CAShapeLayer()
let roundedMaskPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.topLeft, .bottomLeft, .bottomRight],
cornerRadii: CGSize(width: 8, height: 8))
roundedShapeLayer.frame = self.bounds
roundedShapeLayer.fillColor = UIColor.white.cgColor
roundedShapeLayer.path = roundedMaskPath.cgPath
self.layer.insertSublayer(roundedShapeLayer, at: 0)
self.layer.shadowOpacity = 0.4
self.layer.shadowOffset = CGSize(width: -0.1, height: 4)
self.layer.shadowRadius = 3
self.layer.shadowColor = UIColor.lightGray.cgColor
}
}

How to get rounded corners only for topLeft and bottomLeft corners?

I've followed other stackoverflow threads and created CAShapeLayer and added it to button layer.
let bazierPath = UIBezierPath.init(roundedRect: button.bounds, byRoundingCorners: [UIRectCorner.bottomLeft, UIRectCorner.topLeft], cornerRadii: CGSize(width: 10.0, height: 10.0 ))
let shapeLayer = CAShapeLayer()
shapeLayer.frame = button.bounds
shapeLayer.path = bazierPath.cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.lineWidth = 1.0
button.layer.mask = shapeLayer
but the problem is I'm getting corners with clear color but i want them to be green. check for buttons with "Mon" and "Fri" in following image for clear understanding about problem.
in your code you forgot to add the addSublayer to main layer contentView.layer.addSublayer(subLayer) for sample purpose
let contentView = UIView(frame: CGRect(x: CGFloat(50), y: CGFloat(100), width: CGFloat(200), height: CGFloat(100)))
self.view.addSubview(contentView)
let subLayer = CAShapeLayer()
subLayer.fillColor = UIColor.blue.cgColor
subLayer.strokeColor = UIColor.green.cgColor
subLayer.lineWidth = 1.0
subLayer.path = UIBezierPath(roundedRect: contentView.bounds, byRoundingCorners: [UIRectCorner.bottomLeft, UIRectCorner.topLeft], cornerRadii: CGSize(width: 10.0, height: 10.0 )).cgPath
contentView.layer.addSublayer(subLayer)
output
Try to use the following function:
fun createRoundCorners(corners:UIRectCorner, radius: CGFloat)
{
let borderLayer = CAShapeLayer()
borderLayer.frame = self.layer.bounds
borderLayer.strokeColor = // Add your color
borderLayer.fillColor = UIColor.clearColor().CGColor
borderLayer.lineWidth = 1.0
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
borderLayer.path = path.CGPath
self.layer.addSublayer(borderLayer);
}

UIView with shadow, rounded only top corners and masked bottom edge

I'm struggling to achieve the view that would have rounded only top corners and shadow around it. The whole view should be masked at the bottom by the superview to prevent the shadow to overlap following subview (shadow offset should be (0, 0)).
When I use:
// Adding shadow
let contentSubviewLayer = contentSubview.layer
contentSubviewLayer.masksToBounds = false
contentSubviewLayer.shadowOpacity = 0.3
contentSubviewLayer.shadowRadius = 2.5
contentSubviewLayer.shadowOffset = CGSizeMake(0, 0)
contentSubviewLayer.cornerRadius = 5.0
contentSubviewLayer.shadowPath = UIBezierPath(rect: contentSubview.bounds).CGPath
self.layer.masksToBounds = true
I get:
But after adding masking the bottom edge:
// Adding maskView to round only top corners
let maskLayer = CAShapeLayer()
maskLayer.frame = self.contentSubview.bounds
let roundedPath = UIBezierPath(roundedRect: maskLayer.bounds, byRoundingCorners: [UIRectCorner.TopLeft, UIRectCorner.TopRight], cornerRadii: CGSizeMake(CORNER_RADIUS, CORNER_RADIUS))
maskLayer.fillColor = UIColor.whiteColor().CGColor
maskLayer.backgroundColor = UIColor.clearColor().CGColor
maskLayer.path = roundedPath.CGPath
contentSubview.layer.mask = maskLayer
I'm getting:
The desired effect should be the conjunction of the two above and should resemble something like this with shadows around the left, top and right edges:
Please help!
Thank you in advance.
I tend to use an app called PaintCode to generate the Swift code I need for this type of thing. I did something similar recently and it spat this out for me:
let context = UIGraphicsGetCurrentContext()
//// Color Declarations
let chiesi_light_grey = UIColor(red: 0.851, green: 0.851, blue: 0.851, alpha: 1.000)
//// Shadow Declarations
let chiesi_shadow = NSShadow()
chiesi_shadow.shadowColor = chiesi_light_grey.colorWithAlphaComponent(0.8 * CGColorGetAlpha(chiesi_light_grey.CGColor))
chiesi_shadow.shadowOffset = CGSize(width: 0.1, height: 4.1)
chiesi_shadow.shadowBlurRadius = 2
//// Rectangle Drawing
let rectanglePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 50, height: 54), byRoundingCorners: [UIRectCorner.BottomLeft, UIRectCorner.BottomRight], cornerRadii: CGSize(width: 8, height: 8))
rectanglePath.closePath()
CGContextSaveGState(context)
CGContextSetShadowWithColor(context, chiesi_shadow.shadowOffset, chiesi_shadow.shadowBlurRadius, (chiesi_shadow.shadowColor as! UIColor).CGColor)
UIColor.whiteColor().setFill()
rectanglePath.fill()
CGContextRestoreGState(context)
chiesi_light_grey.setStroke()
rectanglePath.lineWidth = 2
rectanglePath.stroke()
Maybe it will help you.

Add border to UITextField

I want to add border to my UITextField like the this image
so I used this code
let rectShape = CAShapeLayer()
rectShape.bounds = self.userNameText.frame
rectShape.position = self.userNameText.center
rectShape.path = UIBezierPath(roundedRect: self.userNameText.bounds, byRoundingCorners: [ UIRectCorner.TopLeft , UIRectCorner.BottomRight ], cornerRadii: CGSize(width: 5.0 , height: 5.0)).CGPath
self.userNameText.layer.backgroundColor = UIColor.redColor().CGColor
//Here I'm masking the textView's layer with rectShape layer
self.userNameText.layer.mask = rectShape
but the result was like this
Did I miss something ??
Give the text field no border, and set its background however you like.
self.textField.borderStyle = .None
let path = UIBezierPath(roundedRect: self.textField.bounds, byRoundingCorners: [ UIRectCorner.TopLeft , UIRectCorner.BottomRight ], cornerRadii: CGSize(width: 8.0 , height: 8.0))
UIGraphicsBeginImageContextWithOptions(self.textField.bounds.size, false, 0)
path.stroke()
self.textField.background = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Try changing the code from
rectShape.path = UIBezierPath(roundedRect: self.userNameText.bounds, byRoundingCorners: [ UIRectCorner.TopLeft , UIRectCorner.BottomRight ], cornerRadii: CGSize(width: 5.0 , height: 5.0)).CGPath
to
rectShape.path = UIBezierPath(roundedRect: self.userNameText.bounds, byRoundingCorners: [ UIRectCorner.BottomRight , UIRectCorner.TopLeft ], cornerRadii: CGSize(width: 5.0 , height: 5.0)).CGPath
and see if the bottom right corner rounds properly like the top left one is now and if the top left looks like the bottom right one is now. It's weird the all of the corners are rounding out like that except for the top left one.
A Recommendation: Try out textFieldEffects. It's a really cool open source project that allows you to create modern, visually appealing text fields in storyboard without any code! I just implemented it in my app and it looks great! The only complaint I have is that I can't get the didBeginEditing and didEndEditing functions to work (maybe a problem on my end).
This seems to get pretty close to what you are looking for:
let rectShape = CAShapeLayer()
rectShape.bounds = self.userNameText.frame
rectShape.position = self.userNameText.center
rectShape.path = UIBezierPath(roundedRect: self.usernameTextField.bounds, byRoundingCorners: [ UIRectCorner.TopLeft , UIRectCorner.BottomRight ], cornerRadii: CGSize(width: 5.0 , height: 5.0)).CGPath
rectShape.fillColor = nil
rectShape.strokeColor = UIColor.redColor().CGColor
self.userNameText.layer.addSublayer(rectShape)
self.userNameText.borderStyle = UITextBorderStyle.None
Here we turned off the border on the UITextField and added the shape as a sublayer.
My code will help you:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.viewTable.bounds
byRoundingCorners:UIRectCornerBottomRight | UIRectCornerTopLeft
cornerRadii:CGSizeMake(13.0, 13.0)];
// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = txtFiled.bounds;
maskLayer.path = maskPath.CGPath;
maskLayer.strokeColor = [UIColor orangeColor].CGColor;
txtFiled.layer.mask = maskLayer;
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = txtFiled.bounds;
shape.path = maskPath.CGPath;
shape.lineWidth = 1.0f;
shape.strokeColor = [UIColor orangeColor].CGColor;
shape.fillColor = [UIColor clearColor].CGColor;
[txtFiled.layer insertSublayer:shape above:maskLayer];
txtFiled.layer.masksToBounds = YES;
txtFiled.layer.shouldRasterize = YES;
txtFiled.layer.rasterizationScale = [[UIScreen mainScreen] scale];

Resources