想使一个 View 的 cornerRadius 生效,需要设置 targetView.layer.masksToBounds = true
或者 targetView.clipsToBounds = true
(其实是同一个东西,表示超出 view 外面的内容是否绘制,默认是 false)
想使一个 View 的 shadow 阴影效果生效,需要设置 targetView.layer.masksToBounds = false
。
所以在同一个 view 里面设置 cornerRadius 和 shadow 就冲突了。
阴影不生效
设置不是都生效的代码所示:
private func shadowAndCornerNotWork() {
let rect = CGRect(x: 100, y: 200, width: 200, height: 200)
let cornerRadius: CGFloat = 20
let imageView = UIImageView(frame: rect)
imageView.image = UIImage(named: "img1") // 设置内容
// cornerRadius ... 起左右
imageView.layer.cornerRadius = cornerRadius
imageView.layer.masksToBounds = true // 使内容的 cornerRadius 有效
// shadow ... 不起左右
imageView.layer.shadowOpacity = 0.7
imageView.layer.shadowRadius = 20
imageView.layer.shadowColor = UIColor.red.cgColor
imageView.layer.shadowOffset = CGSize(width: 0, height: 0)
view.addSubview(imageView)
}

cornerRadius 和 shadow 都生效 1 (规则圆角)
解决办法其实很简单,设置2个 view。
- 一个 view 显示内容,设置 cornerRadius
- 一个 view 显示 shadow
private func shadowAndCornerEfficient() {
let rect = CGRect(x: 100, y: 200, width: 200, height: 200)
let cornerRadius: CGFloat = 40
// 不会离屏渲染
let shadowView = UIView(frame: rect)
shadowView.layer.shadowOpacity = 0.7
shadowView.layer.shadowRadius = cornerRadius
shadowView.layer.shadowColor = UIColor.red.cgColor
shadowView.layer.shadowOffset = CGSize(width: 0, height: 0)
let path0 = UIBezierPath(roundedRect: shadowView.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
shadowView.layer.shadowPath = path0 // 不会离屏渲染
// 不会离屏渲染
let cornerImageView = UIImageView(frame: rect)
cornerImageView.image = UIImage(named: "img1")
cornerImageView.layer.cornerRadius = cornerRadius
cornerImageView.layer.masksToBounds = true
// 3 Add
view.addSubview(shadowView)
view.addSubview(cornerImageView)
}
(可以通过打开模拟器的 Debug -> Color off-screen Rendered 查看。离屏渲染会导致额外的开销,如果很多 view 都开了离屏渲染会导致屏幕卡顿现象)

cornerRadius 和 shadow 都生效 2 (不规则圆角)
func shadowAndCornerNotEfficient() {
let rect = CGRect(x: 100, y: 200, width: 200, height: 200)
let cornerRadius: CGFloat = 40
// 1 shadowView
// 不会离屏渲染
let shadowView = UIView(frame: rect)
shadowView.layer.shadowOpacity = 0.7
shadowView.layer.shadowRadius = cornerRadius
shadowView.layer.shadowColor = UIColor.red.cgColor
shadowView.layer.shadowOffset = CGSize(width: 0, height: 0)
let path0 = UIBezierPath(roundedRect: shadowView.bounds, byRoundingCorners: [.topRight, .bottomLeft], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
shadowView.layer.shadowPath = path0 // 不会离屏渲染
// 2 cornerRadius
let cornerView = UIView(frame: rect)
let cornerLayer = CAShapeLayer()
let path1 = UIBezierPath(roundedRect: cornerView.bounds, byRoundingCorners: [.topRight, .bottomLeft], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
cornerLayer.path = path1
cornerView.layer.mask = cornerLayer // 离屏渲染
cornerView.layer.contents = UIImage(named: "img1")?.cgImage
// 3 Add
view.addSubview(shadowView)
view.addSubview(cornerView)
}
