Skip to content

Instantly share code, notes, and snippets.

@anitaa1990
Last active May 18, 2022 16:22
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save anitaa1990/dd531515427cdecf80560a76f08cc870 to your computer and use it in GitHub Desktop.
Save anitaa1990/dd531515427cdecf80560a76f08cc870 to your computer and use it in GitHub Desktop.
A Swift extension of UIView to display a curved view
import UIKit
extension UIView {
/* Usage Example
* bgView.addBottomRoundedEdge(desiredCurve: 1.5)
*/
func addBottomRoundedEdge(desiredCurve: CGFloat?) {
let offset: CGFloat = self.frame.width / desiredCurve!
let bounds: CGRect = self.bounds
let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2)
let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
// Create the shape layer and set its path
let maskLayer: CAShapeLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
// Set the newly created shape layer as the mask for the view's layer
self.layer.mask = maskLayer
}
}
@chris--young
Copy link

for people trying to add a shadow to this, i was able to do it by using a second view

class CurvedWithShadowView: UIView {
    
    private let shadowView = UIView()
    private let curvedView = UIView()

    init() {
        super.init(frame: .zero)

        shadowView.backgroundColor = .none
        shadowView.configureForAutoLayout()

        curvedView.backgroundColor = .white
        curvedView.configureForAutoLayout()

        addSubview(shadowView)
        addSubview(curvedView)

        configureForAutoLayout()
        setNeedsUpdateConstraints()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // this is using "PureLayout" you could do the same with plain auto layout too
    override func updateConstraints() {
        shadowView.autoPinEdge(toSuperviewEdge: .top)
        shadowView.autoPinEdge(toSuperviewEdge: .bottom)
        shadowView.autoPinEdge(toSuperviewEdge: .left)
        shadowView.autoPinEdge(toSuperviewEdge: .right)

        curvedView.autoPinEdge(toSuperviewEdge: .top)
        curvedView.autoPinEdge(toSuperviewEdge: .bottom)
        curvedView.autoPinEdge(toSuperviewEdge: .left)
        curvedView.autoPinEdge(toSuperviewEdge: .right)

        super.updateConstraints()
    }

    override func layoutSubviews() {
        let offset: CGFloat = frame.width / 0.5
        let mask: CAShapeLayer = CAShapeLayer()

        let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2)
        let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)

        let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
        let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)

        rectPath.append(ovalPath)

        mask.frame = bounds
        mask.path = rectPath.cgPath

        curvedView.layer.mask = mask

        shadowView.layer.shadowPath = rectPath.cgPath
        shadowView.layer.shadowColor = UIColor.black.cgColor
        shadowView.layer.shadowOpacity = 0.15
        shadowView.layer.shadowOffset = .zero
        shadowView.layer.shadowRadius = 4.0
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment