Shadow not being applied if setting corner radius - ios

I am trying to add corner radius to bottmLeft and bottomRight corner and also to add shadow to it. But for some reason if I add those corner radiuses the shadow disappears. What causes this?
This is what I do:
I Have extension:
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
self.layoutIfNeeded()
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Apply corners:
myView.roundCorners([.bottomLeft, .bottomRight], radius: 35)
Add shadow extension:
func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
let layer = self.layer
layer.masksToBounds = false
layer.shadowOffset = offset
layer.shadowColor = color.cgColor
layer.shadowRadius = radius
layer.shadowOpacity = opacity
layer.shadowPath = UIBezierPath.init(roundedRect: layer.bounds, cornerRadius: layer.cornerRadius).cgPath
let backgroundCGColor = self.backgroundColor?.cgColor
self.backgroundColor = nil
layer.backgroundColor = backgroundCGColor
}
And add shadow:
myView.addShadow(offset: CGSize.init(width: 0.0, height: 10.0) , color: UIColor.blue, radius: 35.0, opacity: 1.0)
Why the shadow disappears after adding the rounded corners?

myView.layer.shadowPath needs to be initialized with a UIBezierPath. Just give it the same frame and bounds as myView.

Related

Top right and top left corner radius is not working properly

i wanted add corner radius for only top corners, when i add corner radius to top corners entire view's width is changing, below is the code which i using.
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
layer.mask = mask
mask.path = path.cgPath
layer.masksToBounds = true
}
when i add corner radius to entire layer it is working fine,
layer view.layer.cornerRadius = radius
but i want only top corner radius how can i do this without affecting view width
You can use below function to achieve the behaviour
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let maskPath = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
layer.mask = shape
}
and simply use it like this
someview.roundCorners([.topLeft, .topRight], radius: 25)
but the key thing about applying corner radius is when you are applying!! You can apply it in ViewDidAppear or layoutsubviews method. Basically in those places where you are sure about you will get the accurate width and height of the view. Thanks!!
Use this Extension
extension UIView
{
#discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
}
And You can call By Below code
self.yourView.round(corners: [.topLeft,.topRight], radius: 20, borderColor: .clear, borderWidth: 0)

Shadow does not work with round corner on top Tableview

Hello in my condition i am using two conditions ,one to make round corner only top view after that shadow on the top only , only one condition works if i am adding code for shadow it does not work but i remove corner code then shadow works please guide me
for round corner i am using this extension
extension UIView {
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
and for shadow
func shadowToUIView( uiview : UIView){
uiview.layer.shadowColor = UIColor.darkGray.cgColor
uiview.layer.shadowOpacity = 0.50
uiview.layer.shadowOffset = CGSize(width: 1, height: 1)
uiview.layer.shadowRadius = 5
uiview.layer.shouldRasterize = false
}
and in cell for row i am using this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell
cell.firstView.roundCorners(corners: [.topLeft,.topRight], radius: 25.0)
shadowToUIView(uiview: cell.firstView)
HomeMenu.openMenuCard(cell:cell, indexPath:indexPath, firstViewMain:firstViewMain, openedTab: openedTab)
return cell
}
after adding replied code
Here is the method that will allow you to make the UIView round with shadow:
extension UIView {
func addShadow(cornerRadius: CGFloat, maskedCorners: CACornerMask, color: UIColor, offset: CGSize, opacity: Float, shadowRadius: CGFloat) {
self.layer.cornerRadius = cornerRadius
self.layer.maskedCorners = maskedCorners
self.layer.shadowColor = color.cgColor
self.layer.shadowOffset = offset
self.layer.shadowOpacity = opacity
self.layer.shadowRadius = shadowRadius
}
}
Use:
For rounding all the corners:
<your_view_object>.addShadow(cornerRadius: 10.0, maskedCorners: [.layerMaxXMaxYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMinYCorner], color: AppColors.themeBlack.withAlphaComponent(0.6), offset: CGSize.zero, opacity: 0.4, shadowRadius: 4.0)
For rounding only top corners:
<your_view_object>.addShadow(cornerRadius: 10.0, maskedCorners: [.layerMaxXMinYCorner, .layerMinXMinYCorner], color: AppColors.themeBlack.withAlphaComponent(0.6), offset: CGSize.zero, opacity: 0.4, shadowRadius: 4.0)
For rounding only bottom corners:
<your_view_object>.addShadow(cornerRadius: 10.0, maskedCorners: [.layerMaxXMaxYCorner, .layerMinXMaxYCorner], color: AppColors.themeBlack.withAlphaComponent(0.6), offset: CGSize.zero, opacity: 0.4, shadowRadius: 4.0)
For making the shadow as per you requirement change the others parameters.
Doc for layer.mask states:
"The layer’s alpha channel determines how much of the layer’s content and background shows through. Fully or partially opaque pixels allow the underlying content to show through, but fully transparent pixels block that content. The default value of this property is nil. When configuring a mask, remember to set the size and position of the mask layer to ensure it is aligned properly with the layer it masks."
So, I added
mask.frame = self.bounds.offsetBy(dx: -6.0, dy: -6.0)
Works correctly (need to adapt offset values).
Good Question..!!!
I have same requirement in my recent school application.Here's
Best solutions which will working as per your requirement.
Please use below ShadowView class for rounded shadow.
https://ibb.co/3S0rD7s
https://ibb.co/qCtrGqz
class ShadowView:UIView{[![enter image description here][1]][1]
private var theShadowLayer: CAShapeLayer?
override func layoutSubviews() {
super.layoutSubviews()
let rounding = CGFloat.init(10.0)
var shadowLayer = CAShapeLayer.init()
shadowLayer.name = "ShadowLayer1"
shadowLayer.path = UIBezierPath.init(roundedRect: bounds, cornerRadius: rounding).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowColor = UIColor.init(red: 60.0/255.0, green: 64.0/255.0, blue: 67.0/255.0, alpha:0.3).cgColor
shadowLayer.shadowRadius = CGFloat.init(2.0)
shadowLayer.shadowOpacity = Float.init(0.5)
shadowLayer.shadowOffset = CGSize.init(width: 0.0, height: 1.0)
if let arraySublayer1:[CALayer] = self.layer.sublayers?.filter({$0.name == "ShadowLayer1"}),let sublayer1 = arraySublayer1.first{
sublayer1.removeFromSuperlayer()
}
self.layer.insertSublayer(shadowLayer, below: nil)
shadowLayer = CAShapeLayer.init()
shadowLayer.name = "ShadowLayer2"
shadowLayer.path = UIBezierPath.init(roundedRect: bounds, cornerRadius: rounding).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowColor = UIColor.init(red: 60.0/255.0, green: 64.0/255.0, blue: 67.0/255.0, alpha:0.15).cgColor
shadowLayer.shadowRadius = CGFloat.init(6.0)
shadowLayer.shadowOpacity = Float.init(0.5)
shadowLayer.shadowOffset = CGSize.init(width: 0.0, height: 2.0)
if let arraySublayer2:[CALayer] = self.layer.sublayers?.filter({$0.name == "ShadowLayer2"}),let sublayer2 = arraySublayer2.first{
sublayer2.removeFromSuperlayer()
}
self.layer.insertSublayer(shadowLayer, below: nil)
}
}
Easy to implement
Simple design make One Containerview inheritance of class ShadowView And add Sub container view (rounded corner view)..That’s it..!!!..Run it..!!

How to initialize button borders generated by code In Swift 4

I used the code to create the button border.
I have to change the shape of the button border for some reason.
However, the border generated by mask is not initialized with the following code.
button.backgroundColor = .clear
button.layer.CornerRadius = 0
In ViewController.swift :
#IBOutlet weak var btnDelete: UIButton!
func FirstChange() {
btnDelete.layer.borderWidth = 0
btnDelete.layer.cornerRadius = 0
btnDelete.layer.borderColor = UIColor(rgb: 0xFFFFFF).cgColor
// Draw the border again
btnDelete.round(corners: [.topRight, .bottomRight], radius: 50, borderColor: UIColor(rgb: 0xced4da), borderWidth: 1)
}
func SecChange() {
btnDelete.backgroundColor = .clear // not work
// Draw the border again
btnDelete.layer.borderColor = UIColor(rgb: 0xced4da).cgColor
btnDelete.layer.borderWidth = 1
btnDelete.layer.cornerRadius = 18
}
In UIView.swift :
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
#discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
The second time draw the border(run SecChange()), it overlaps with the first border.
Please help me to initialize the first border I painted.
(Running SecChange() and running FirstChange() initializes the border successfully.)
since you are adding a CAShapeLayer to the UIButton you need to remove this layer from the button. For this you could give the layer a name and add a new method to remove the layer and call that new method in your second change. Additionally you should remove the border layer when calling round(corners:radius:borderColor:borderWidth:) again, otherwise you would end up with another layer on top.
func SecChange() {
btnDelete.removeBorderLayer() //remove border layer if existing
// Draw the border again
btnDelete.layer.borderColor = UIColor.gray.cgColor
btnDelete.layer.borderWidth = 1
btnDelete.layer.cornerRadius = 18
}
extension UIView {
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
#discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
removeBorderLayer()
let borderLayer = CAShapeLayer()
borderLayer.name = "borderLayer"
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
func removeBorderLayer() {
if let borderLayer = layer.sublayers?.first(where: { $0.name == "borderLayer" }) {
borderLayer.removeFromSuperlayer()
}
}
}
Best,
Carsten

Swift3 round two corners of UIView

I know this question already asked so many times and their solutions also available but nothing works for me.
I am using Swift3 and I want to round any two sides of UIView for this purpose I found the following solution
Create a rectangle with just two rounded corners in swift?
and following is my code snippet of the above solution
extension UIView {
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
func round(corners: UIRectCorner, radius: CGFloat) -> Void {
layer.addSublayer(_round(corners: corners, radius: radius))
}
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
layer.masksToBounds = true
layer.cornerRadius = diameter / 2
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor;
}
}
private extension UIView {
func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
}
This is the result I got. I don't know what I am doing wrong.
Can anyone please solve this?
Code tested and worked in Swift 3.
Use below extension to create roundCorners.
extension UIView {
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Usage: in viewDidLoad
yourViewName.roundCorners(corners: [.topRight, .bottomLeft], radius: 10)
Output:
First of all you will need to Make IBOutlet for that Textfield or Button which you
need to Be Rounded Corner
Go to The ViewDidLoad() Method
Write the name of IBOutLet
Example Code mybutton.layer.cornerRadius=10
Here is the Solution to Your Problem

Create a rectangle with just two rounded corners in swift?

I need to create a rectangle that have just two rounded corners in swift (Objective C code also ok).
At the moment my code is creating two rectangles with
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 5, 5, nil);
and
CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 0, 0, nil);
and merging them (to have two right angle corners and two rounded ones) but I am not happy with the code and I am pretty sure there should be much better ways to do it.
I am new to iOS and graphical development and swift.
Update: See this answer below for Swift 4 / iOS 11 which is much, much easier
Here's a quick Swift 3 extension you can use to do rounding and optional borders.
Note: if you're using autolayout, you may need to call this in one of the view lifecycle callbacks like viewDidLayoutSubviews or layoutSubviews after the view has been constrained.
import UIKit
extension UIView {
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
func round(corners: UIRectCorner, radius: CGFloat) {
_ = _round(corners: corners, radius: radius)
}
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
layer.masksToBounds = true
layer.cornerRadius = diameter / 2
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor;
}
}
private extension UIView {
#discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
}
Swift 4+, iOS 11+
If you already have a UIView named myView referenced as an IBOutlet, try adding the following two lines in ViewDidLoad() or wherever it's being loaded:
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
You can change the array [] to any combination of MinX, MinY, MaxX, and MaxY to select the desired corners. The above example rounds the bottom two corners.
This is just another approach, can be a bit simpler depending on your design.
In Swift 2.3 you could do so by
let maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
view.layer.mask = shape
In Objective-C you could use the UIBezierPath class method
bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
example implementation-
// set the corner radius to the specified corners of the passed container
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
and call the above method as-
[self setMaskTo:anyView byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];
Swift 3 - Useful UIView extension when you need to round specific corners of some views:
extension UIView {
func round(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
then just use it like this:
someView.round(corners: [.topLeft, .topRight], radius: 5)
Building on top of Sanjay's excellent answer, I wrote a quick CALayer extension for Swift 2.3, in case you need to do this sort of "only round some corners" thing more than once.
extension CALayer {
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let maskPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
mask = shape
}
}
Usage:
myView.layer.roundCorners([.TopLeft, .TopRight], radius: myCornerRadius)
Swift 3.0 (In this example the bounds came from the view not from the layer. Using the bounds from the view make this code to work with views in a UITableViewCell.):
func roundCorners(corners: UIRectCorner, radius: CGFloat, viewBounds: CGRect) {
let maskPath = UIBezierPath(roundedRect: viewBounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
mask = shape
}
Usage:
myView.layer.roundCorners(corners: [.topLeft, .topRight], radius: myCornerRadius, viewBounds: bounds)
Up-to-date for 2021 ...
Please note that syntax/systems have changed a lot since this question was asked a long time ago!
import UIKit
#IBDesignable
class RoundedEnds: UIView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
let r = self.bounds.size.height / 2
let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:r)
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
For only some corners, just change the path line of code to:
let path = UIBezierPath(
roundedRect: self.bounds,
byRoundingCorners: [.topLeft,.topRight],
cornerRadii: CGSize(width: r, height: r))
iOS 11+ Only | You can check iOS usage stats here
Explanation
Since the CACornerMask rawValue is an UInt you know that a CACornerMask rawValue is the sum of each CACornerMask.Element rawValue
More specifically:
TopLeft (layerMinXMinYCorner) = 1
TopRight (layerMaxXMinYCorner) = 2
BottomLeft (layerMinXMaxYCorner) = 4
BottomRight (layerMaxXMaxYCorner) = 8
So for example if you want top left and top right corners you can just type CACornerMask(rawValue: 3).
 Example
Below is a simple extension of UIView
extension UIView {
enum Corner:Int {
case bottomRight = 0,
topRight,
bottomLeft,
topLeft
}
private func parseCorner(corner: Corner) -> CACornerMask.Element {
let corners: [CACornerMask.Element] = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]
return corners[corner.rawValue]
}
private func createMask(corners: [Corner]) -> UInt {
return corners.reduce(0, { (a, b) -> UInt in
return a + parseCorner(corner: b).rawValue
})
}
func roundCorners(corners: [Corner], amount: CGFloat = 5) {
layer.cornerRadius = amount
let maskedCorners: CACornerMask = CACornerMask(rawValue: createMask(corners: corners))
layer.maskedCorners = maskedCorners
}
}
You can use it this like:
let myRect = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
myRect.roundCorners(corners: [.topRight, .topLeft])
Here is what you do in Swift 2.0
var maskPath = UIBezierPath(roundedRect: anyView.bounds,
byRoundingCorners: [.BottomLeft, .BottomRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))
Swift 4:
let maskPath = UIBezierPath(
roundedRect: view.bounds,
byRoundingCorners: [.allCorners],
cornerRadii: CGSize(width: 10.0, height: 10.0)
)
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
view.layer.mask = shape
Updated iWasRobbed's answer to work with the Swift 3.0 GM version:
import UIKit
extension UIView {
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
func round(corners: UIRectCorner, radius: CGFloat) {
_round(corners: corners, radius: radius)
}
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
let mask = _round(corners: corners, radius: radius)
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
}
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
layer.masksToBounds = true
layer.cornerRadius = diameter / 2
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor;
}
}
private extension UIView {
#discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
return mask
}
func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = borderWidth
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
}
}
extension CACornerMask {
public static var leftBottom : CACornerMask { get { return .layerMinXMaxYCorner}}
public static var rightBottom : CACornerMask { get { return .layerMaxXMaxYCorner}}
public static var leftTop : CACornerMask { get { return .layerMaxXMinYCorner}}
public static var rightTop : CACornerMask { get { return .layerMinXMinYCorner}}
}
extension CALayer {
func roundCorners(_ mask:CACornerMask,corner:CGFloat) {
self.maskedCorners = mask
self.cornerRadius = corner
}
}
self.viewBack.layer.roundCorners([.leftBottom,.rightBottom], corner: 23)
In summary, you can create pretty extension like this:
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: Double) {
let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
layer.mask = shape
}
}
Use it like this:
view.roundCorners([.topRight, .bottomRight], radius: 10)
Here is all corners values:
.topLeft
.topRight
.bottomLeft
.bottomRight
view.layer.cornerRadius = 10.0
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
Best way to do it!
Swift 5: For top-left and top-right round corners.
yourView.layer.cornerRadius = 12
yourView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
Objective-C version of iWasRobbed's answer:
UIView+RoundCorners.h
#import <UIKit/UIKit.h>
#interface UIView (RoundCorners)
/**
Rounds the given set of corners to the specified radius
- parameter corners: Corners to round
- parameter radius: Radius to round to
*/
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius;
/**
Rounds the given set of corners to the specified radius with a border
- parameter corners: Corners to round
- parameter radius: Radius to round to
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
/**
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
- parameter diameter: The view's diameter
- parameter borderColor: The border color
- parameter borderWidth: The border width
*/
- (void)fullyRoundWithDiameter:(CGFloat)diameter borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
#end
UIView+RoundCorners.m
#import "UIView+RoundCorners.h"
#implementation UIView (RoundCorners)
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
[self _roundCorners:corners radius:radius];
}
- (void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
CAShapeLayer *mask = [self _roundCorners:corners radius:radius];
[self addBorderWithMask:mask borderColor:borderColor borderWidth:borderWidth];
}
- (void)fullyRoundWithDiameter:(CGFloat)diameter borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
self.layer.masksToBounds = YES;
self.layer.cornerRadius = diameter / 2;
self.layer.borderWidth = borderWidth;
self.layer.borderColor = borderColor.CGColor;
}
- (CAShapeLayer *)_roundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = path.CGPath;
self.layer.mask = mask;
return mask;
}
- (void)addBorderWithMask:(CAShapeLayer *)mask borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
CAShapeLayer *borderLayer = [CAShapeLayer layer];
borderLayer.path = mask.path;
borderLayer.fillColor = UIColor.clearColor.CGColor;
borderLayer.strokeColor = borderColor.CGColor;
borderLayer.lineWidth = borderWidth;
borderLayer.frame = self.bounds;
[self.layer addSublayer:borderLayer];
}
#end
One simple hack could be as following. Take views like below example in image. Red View will have rounded corners and Yellow View (inside Red View) will prevent the corners to be rounded
Now write below code for Red View.
self.myView.layer.cornerRadius = 15
Make sure you don't write any code as clipsToBounds = true or masksToBounds = true.
Below image is the result
Placement of Yellow View will decide, which 2 corners will not be rounded. Hope this is easy to implement.

Resources