使用 UIBezierPath 为带有阴影的选定边添加圆角半径
Adding Corner radius for selected edges with shadow using UIBezierPath
我正在尝试在我的视图中添加阴影。它有 3 个圆形边缘。实现这个 UIBezierPath,然后将这个路径的 CAShapelayer 设置为视图层上的遮罩。现在,如果我试图在此视图上添加阴影,它不会显示。我已经经历了类似的问题和建议的答案,但在我的情况下没有任何效果。以下是我的实现:
class BubbleView: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
}
override func layoutSubviews() {
super.layoutSubviews()
self.updateContainerLayer()
}
func updateContainerLayer() {
let brazierPath: UIBezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
//1
let shapeLayer = CAShapeLayer()
shapeLayer.path = brazierPath.cgPath
self.layer.mask = shapeLayer
//2
self.layer.shadowColor = UIColor(r: 0, g: 0, b: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
self.layer.shadowRadius = 1.5
self.layer.shadowPath = brazierPath.cgPath
//3
self.layer.masksToBounds = true
self.clipsToBounds = false
//4
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
如果您的目标是 iOS 11+ 您可以使用图层的 .maskedCorners
属性:
class BubbleView: UIView {
// don't override draw()
// override func draw(_ rect: CGRect) {
// super.draw(rect)
// }
override func layoutSubviews() {
super.layoutSubviews()
self.updateContainerLayer()
}
func updateContainerLayer() {
let brazierPath: UIBezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
//1
// let shapeLayer = CAShapeLayer()
// shapeLayer.path = brazierPath.cgPath
// self.layer.mask = shapeLayer
// iOS 11+ use .maskedCorners
self.layer.cornerRadius = 15.0
self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
//2
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
self.layer.shadowRadius = 1.5
self.layer.shadowPath = brazierPath.cgPath
//3
self.layer.masksToBounds = true
self.clipsToBounds = false
//4
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
结果:
夸张的结果 .shadowOffset = CGSize(width: -10.0, height: 10.5)
以便于看到阴影:
如果您需要允许更早的 iOS 版本,我 相信 您需要使用容器视图方法。
编辑:
另一种方法,对阴影使用 "container" 视图。这将适用于早于 11 的 iOS...它对 "content view" 掩码和阴影路径使用相同的 UIBezierPath
:
class BubbleView: UIView {
let contentView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
addSubview(contentView)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
])
self.clipsToBounds = false
backgroundColor = .clear
contentView.backgroundColor = .red
// set non-changing properties here
contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
// exaggerated shadow offset so we can see it easily
//self.layer.shadowOffset = CGSize(width: -10.0, height: 10.5)
self.layer.shadowRadius = 1.5
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
override func layoutSubviews() {
super.layoutSubviews()
let bezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierPath.cgPath
contentView.layer.mask = shapeLayer
self.layer.shadowPath = bezierPath.cgPath
}
}
与 11+ 示例一样,结果:
并且结果带有夸张的 .shadowOffset = CGSize(width: -10.0, height: 10.5)
以便于看到阴影:
我正在尝试在我的视图中添加阴影。它有 3 个圆形边缘。实现这个 UIBezierPath,然后将这个路径的 CAShapelayer 设置为视图层上的遮罩。现在,如果我试图在此视图上添加阴影,它不会显示。我已经经历了类似的问题和建议的答案,但在我的情况下没有任何效果。以下是我的实现:
class BubbleView: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
}
override func layoutSubviews() {
super.layoutSubviews()
self.updateContainerLayer()
}
func updateContainerLayer() {
let brazierPath: UIBezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
//1
let shapeLayer = CAShapeLayer()
shapeLayer.path = brazierPath.cgPath
self.layer.mask = shapeLayer
//2
self.layer.shadowColor = UIColor(r: 0, g: 0, b: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
self.layer.shadowRadius = 1.5
self.layer.shadowPath = brazierPath.cgPath
//3
self.layer.masksToBounds = true
self.clipsToBounds = false
//4
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
如果您的目标是 iOS 11+ 您可以使用图层的 .maskedCorners
属性:
class BubbleView: UIView {
// don't override draw()
// override func draw(_ rect: CGRect) {
// super.draw(rect)
// }
override func layoutSubviews() {
super.layoutSubviews()
self.updateContainerLayer()
}
func updateContainerLayer() {
let brazierPath: UIBezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
//1
// let shapeLayer = CAShapeLayer()
// shapeLayer.path = brazierPath.cgPath
// self.layer.mask = shapeLayer
// iOS 11+ use .maskedCorners
self.layer.cornerRadius = 15.0
self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
//2
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
self.layer.shadowRadius = 1.5
self.layer.shadowPath = brazierPath.cgPath
//3
self.layer.masksToBounds = true
self.clipsToBounds = false
//4
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
结果:
夸张的结果 .shadowOffset = CGSize(width: -10.0, height: 10.5)
以便于看到阴影:
如果您需要允许更早的 iOS 版本,我 相信 您需要使用容器视图方法。
编辑:
另一种方法,对阴影使用 "container" 视图。这将适用于早于 11 的 iOS...它对 "content view" 掩码和阴影路径使用相同的 UIBezierPath
:
class BubbleView: UIView {
let contentView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
addSubview(contentView)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
])
self.clipsToBounds = false
backgroundColor = .clear
contentView.backgroundColor = .red
// set non-changing properties here
contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize(width: 0.0, height: 0.5)
// exaggerated shadow offset so we can see it easily
//self.layer.shadowOffset = CGSize(width: -10.0, height: 10.5)
self.layer.shadowRadius = 1.5
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
override func layoutSubviews() {
super.layoutSubviews()
let bezierPath = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomRight, .bottomLeft, .topLeft],
cornerRadii: CGSize(width: 15.0, height: 0.0))
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierPath.cgPath
contentView.layer.mask = shapeLayer
self.layer.shadowPath = bezierPath.cgPath
}
}
与 11+ 示例一样,结果:
并且结果带有夸张的 .shadowOffset = CGSize(width: -10.0, height: 10.5)
以便于看到阴影: