如何解决CAShapeLayer显示在视图上方的问题
解决CAShapeLayer阴影显示在视图上方的问题
问题根源
你的代码里有两个关键错误导致阴影显示异常:
- 设置了
self.clipsToBounds = true,这会把视图图层的所有内容(包括子图层)裁剪到视图边界内,阴影的模糊扩散部分会被完全切掉; - 通过
layer.addSublayer(shadowLayer)添加阴影层,会让阴影层显示在视图原有内容的上方,所以看起来阴影在视图上面。
修复方案
方案一:将阴影层挂载到父视图,置于当前视图下方
这个方案能保证视图自身的圆角裁剪正常,同时阴影完整显示在视图下方:
func drawShadowWithCornerRadius(cornerRadius: CGFloat, shadowColor: UIColor, shadowOffSet: CGSize, shadowOpacity: Float, shadowRadius: CGFloat) { // 给当前视图设置圆角并裁剪内部内容 self.layer.cornerRadius = cornerRadius self.layer.masksToBounds = true let shadowLayer = CAShapeLayer() // 扩展阴影路径范围,避免阴影模糊部分被父视图裁剪 let shadowRect = self.bounds.insetBy(dx: -shadowRadius, dy: -shadowRadius) shadowLayer.path = UIBezierPath(roundedRect: shadowRect, cornerRadius: cornerRadius).cgPath shadowLayer.shadowColor = shadowColor.cgColor shadowLayer.shadowPath = shadowLayer.path shadowLayer.shadowOffset = shadowOffSet shadowLayer.shadowOpacity = shadowOpacity shadowLayer.shadowRadius = shadowRadius // 将阴影层添加到父视图图层,放在当前视图的下方 self.superview?.layer.insertSublayer(shadowLayer, below: self.layer) // 绑定阴影层的frame与当前视图同步 shadowLayer.frame = self.frame }
方案二:调整当前视图的图层层级,将阴影层置于最底层
这个方案不需要依赖父视图,但要关闭视图自身的裁剪:
func drawShadowWithCornerRadius(cornerRadius: CGFloat, shadowColor: UIColor, shadowOffSet: CGSize, shadowOpacity: Float, shadowRadius: CGFloat) { // 关闭视图裁剪,让阴影能显示在边界外 self.clipsToBounds = false self.layer.masksToBounds = false let shadowLayer = CAShapeLayer() shadowLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: cornerRadius).cgPath shadowLayer.fillColor = self.backgroundColor?.cgColor ?? UIColor.clear.cgColor shadowLayer.shadowColor = shadowColor.cgColor shadowLayer.shadowPath = shadowLayer.path shadowLayer.shadowOffset = shadowOffSet shadowLayer.shadowOpacity = shadowOpacity shadowLayer.shadowRadius = shadowRadius shadowLayer.cornerRadius = cornerRadius // 将阴影层插入到当前视图图层的最底部 self.layer.insertSublayer(shadowLayer, at: 0) // 确保视图的子内容显示在阴影层上方 self.subviews.forEach { $0.layer.zPosition = 1 } }
额外注意
- 如果父视图设置了
clipsToBounds = true,阴影超出父视图的部分会被裁剪,需要同时关闭父视图的裁剪; - 当视图的frame发生变化时(比如屏幕旋转、布局更新),需要重新调用这个方法更新阴影层的路径和frame,避免阴影错位。
内容的提问来源于stack exchange,提问作者Rhytam Gulati
相关产品推荐
相关产品推荐

