Skip to content

Instantly share code, notes, and snippets.

@AlexChekel1337
Created August 21, 2024 18:56
Show Gist options
  • Save AlexChekel1337/69e8873bc0cb8e82112c964b8c53f7ec to your computer and use it in GitHub Desktop.
Save AlexChekel1337/69e8873bc0cb8e82112c964b8c53f7ec to your computer and use it in GitHub Desktop.
A view that combines shadow, corner radius, and translucent background into one view
class ShadowCutoutView: UIView {
var contentView: UIView? {
didSet {
oldValue?.removeFromSuperview()
guard let contentView else {
return
}
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(contentView)
}
}
let shadowLayer = CALayer()
private let shadowMaskLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
shadowLayer.mask = shadowMaskLayer
layer.addSublayer(shadowLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
let shadowCornerRadius = contentView?.layer.cornerRadius ?? 0
let shadowPadding = shadowLayer.shadowRadius * 4
shadowLayer.frame = bounds
shadowLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: shadowCornerRadius).cgPath
let maskFrame = CGRect(
x: -shadowPadding,
y: -shadowPadding,
width: bounds.width + shadowPadding * 2,
height: bounds.height + shadowPadding * 2
)
let maskPath = UIBezierPath(rect: CGRect(origin: .zero, size: maskFrame.size))
let cutoutPath = UIBezierPath(
roundedRect: bounds.offsetBy(dx: shadowPadding, dy: shadowPadding),
cornerRadius: shadowCornerRadius
)
maskPath.append(cutoutPath.reversing())
shadowMaskLayer.frame = maskFrame
shadowMaskLayer.path = maskPath.cgPath
}
}
// Shadow parameters are adjusted through `shadowLayer` property instead
let view = ShadowCutoutView()
view.shadowLayer.shadowOffset = .zero
view.shadowLayer.shadowColor = UIColor.black.cgColor
view.shadowLayer.shadowRadius = 20
view.shadowLayer.shadowOpacity = 1
// Shadow corner radius is determined by corner radius of the content view
let contentView = UIView()
contentView.clipsToBounds = true
contentView.layer.cornerRadius = 20
view.contentView = contentView
@AlexChekel1337
Copy link
Author

This view allows you to have shadow, corner radius, and a translucent background all at the same time. You can adjust shadow parameters by changing corresponding properties on shadowLayer instead of regular layer property.
Shadow automatically adjusts its corner radius based on corner radius of its content view.

Translucent UIView UIVisualEffectView
translucent blur

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