I have the following code that is intended to round just the bottom corners of a UIImage via a layer mask. The code works fine as far as rounding the corners go, but when I do so, it is creating a strange offset and I can't figure out where it's coming from.
Here it is, without the code (Notice how it lines up on the bottom with the purple rounded rectangle sitting behind it):
And here it is with the layer mask code:
Here is the code:
//This section sets the corner radius & shadow of the purple rectangle.
totalTankRep.layer.cornerRadius = 8
totalTankRep.clipsToBounds = true
totalTankRep.layer.masksToBounds = false;
totalTankRep.layer.shadowOffset = CGSize(width: 5.0, height: 5.0);
totalTankRep.layer.shadowRadius = 8;
totalTankRep.layer.shadowOpacity = 0.25;
//This defaults the green rectangle to 0 (for the top corners)
oilLevelRep.layer.cornerRadius = 0
//This applies a layer mask that rounds the corners
let maskPath = UIBezierPath(roundedRect: oilLevelRep.bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 8.0, height: 0.0))
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
oilLevelRep.layer.mask = maskLayer
view.addSubview(oilLevelRep)
Any idea what's going on here, and how I can fix this?
Related
I am trying to set top left and top right corners to tab bar along with shadow.
I am using below function which is in my UIView extension:
func addShadowWithCurve(usingCorners corners : UIRectCorner,cornerRadii : CGSize, shadowColor:UIColor,shadowOpacity:Float,shadowRadius:CGFloat,shadowOffset:CGSize){
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: cornerRadii)
layer.masksToBounds = false
let frameLayer = CAShapeLayer()
frameLayer.path = path.cgPath
frameLayer.shadowPath = path.cgPath
frameLayer.lineWidth = 1
frameLayer.strokeColor = RRSTokens.colorGrey10.cgColor
frameLayer.fillColor = backgroundColor?.cgColor
frameLayer.shadowOffset = shadowOffset
frameLayer.shadowOpacity = shadowOpacity
frameLayer.shadowRadius = shadowRadius
frameLayer.shadowColor = shadowColor.cgColor
layer.mask = frameLayer
layer.insertSublayer(frameLayer, at: 0)
}
But the result is not expected, there is a black border line visible at the top of tab bar. I have tried multiple attempts to play around layer properties to remove that black line but no luck. This is what it looks like:
Your code is perfect just add below line to your code:
self.tabBar.barStyle = .blackOpaque
Hope it'll solve your problem. Thank you.
I am creating a TabBar with top left and top right corners rounded.
I'm using a layer mask to achieve this and it works fine, however I need the mask color to be white (its transparent showing the VC background color with the below code).
Is it possible to set the mask background color white with below approach?
I've tried setting layer and layer.mask background colours but with no success (I can't change the VC background color).
current code:
self.tabBar.layer.masksToBounds = true
self.tabBar.isTranslucent = true
self.tabBar.barStyle = .default
self.tabBar.layer.cornerRadius = 28
self.tabBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
Thanks.
If you want to set background color to layer mask, you need another layer
Is this the effect you needed?
You may try this:
extension UITabBar {
func roundCorners(corners: UIRectCorner, backgroundColor: UIColor, cornerColor: UIColor, radius: Int = 20) {
self.backgroundColor = cornerColor
let parentLayer = CALayer()
parentLayer.frame = bounds
parentLayer.backgroundColor = backgroundColor.cgColor
layer.insertSublayer(parentLayer, at: 0)
let maskPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.frame = bounds
mask.path = maskPath.cgPath
parentLayer.mask = mask
}
}
This question already has answers here:
IOS: Is possible to rounder radius with different value in each corner
(3 answers)
Closed 4 years ago.
I need to round top corners of a view with any value and also bottom corners of the same view with a different value. Here, I have the code I thought it would solve this. But it doesn't work... Any idea?
bottomPath = UIBezierPath(roundedRect:self.bounds,
byRoundingCorners:[.bottomLeft, .bottomRight],
cornerRadii: CGSize(width: radius, height: radius))
topPath = UIBezierPath(roundedRect:self.bounds,
byRoundingCorners:[.topLeft, .topRight],
cornerRadii: CGSize(width: radius, height: radius))
bottomPath.append(topPath)
maskLayer = CAShapeLayer()
maskLayer?.path = bottomPath.cgPath
self.layer.mask = maskLayer
If I comment bottomPath or topPath I get top or bottom corners rounded, but never both of them
Thank you
I don't believe there is any system call to create a rounded rectangle with different corner radii for each corner. The function UIBezierPath(roundedRect:byRoundingCorners:cornerRadii:) that you are using will create a rounded rectangle with some corners rounded and some not, but the corners you ask to round will all have the same radius.
If you want to create a path with different corners rounded to different radii I'm pretty sure you'll have to build such a path yourself using arcs for each corner and line segments for the flat sides of the rounded rectangle. (You'd draw a closed path composed of an arc with an angle of ∏/2, then a line segment, and repeat that 4 times. The center of each arc would be that corner of the rectangle, inset by the corner radius in both dimensions. It helps to diagram it out on graph paper.)
EDIT:
With a little digging I found this post that includes code to generate a rounded rect with a different corner radius for each corner:
IOS: Is possible to rounder radius with different value in each corner
use the function viewDidLayoutSubviews and call your function inside, to change into round corner.
Example :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
headerView.roundedButtonForTopRightTopLeft()
view.setNeedsLayout()
view.setNeedsDisplay()
}
extension UIView {
func roundedButtonForTopRightTopLeft(){
let maskPath1 = UIBezierPath(roundedRect: bounds,
byRoundingCorners: [.topRight , .topLeft],
cornerRadii: CGSize(width: 8, height: 8))
let maskLayer1 = CAShapeLayer()
maskLayer1.frame = bounds
maskLayer1.path = maskPath1.cgPath
layer.mask = maskLayer1
}
}
Call after that
override func layoutSubviews() {
//here call round func
self.layoutIfNeeded()
super.layoutSubviews()
}
I'm trying to mask a view with a rounded rectangle UIBezierPath. I want the mask to look exactly the same as if I were just setting layer.cornerRadius:
let frame = CGRect(x: 0, y: 0, width: 80, height: 80)
let cornerRadius = 30
Using cornerRadius:
let view = UIView(frame: frame)
view.layer.cornerRadius = cornerRadius
Using UIBezierPath mask:
let view = UIView(frame: frame)
let maskingShape = CAShapeLayer()
maskingShape.path = UIBezierPath(roundedRect: frame, cornerRadius: cornerRadius).cgPath
view.layer.mask = maskingShape
The resulting rounded rects are completely different. The standard cornerRadius works as expected while the bezier path just snaps to a full circle at a certain radius.
Apparently, this is intended behaviour from iOS 7.
How then do I draw a standard rounded rectangle with a bezier path?
I found this category but this has to be a joke right? Is there no simpler way? :(
Related question.
Good afternoon,
How do i achieve something like this in swift 3?
circle with blurred drop shadow beneath
The center of the shadow is about 30px from the bottom of the circle. I have tried using the shadow trick but i wasn't able to squish the shadow. I also tried using a picture from photoshop but the blur becomes nasty when scaled up.
let rect = CGRect(x: 0, y: midView.frame.minY, width: (midView.bounds.width), height: 20.0)
let elipticalPath = UIBezierPath(ovalIn: rect).cgPath
let maskLayer = CAGradientLayer()
maskLayer.frame = midView.bounds
maskLayer.shadowRadius = 15
maskLayer.shadowPath = elipticalPath
maskLayer.shadowOpacity = 0.7
maskLayer.shadowOffset = CGSize.zero
maskLayer.shadowColor = UIColor.gray.cgColor
midView.layer.addSublayer(maskLayer)