如何为应用了渐变效果的UIView设置圆角?
给带渐变的UIView添加圆角的两种可行方案
直接设置layer.cornerRadius对你的自定义View没用,因为你是在draw(_ rect:)方法里直接绘制渐变内容,这部分内容不会自动被图层的圆角遮罩裁剪。下面给你两种实用的解决方案:
方案一:改用CAGradientLayer实现渐变(推荐)
这种方式更符合iOS的图层设计,性能更高,也更容易控制圆角、阴影等效果。我们可以把渐变作为一个子图层添加到View,然后通过图层的圆角属性来裁剪:
import UIKit @IBDesignable class PlayerCellView: UIView { // 用@IBInspectable让属性在Storyboard里可编辑 @IBInspectable var startColor: UIColor = UIColor(red:0.20, green:0.75, blue:1.00, alpha:1.00) { didSet { updateGradient() } } @IBInspectable var endColor: UIColor = UIColor(red:0.07, green:0.42, blue:1.00, alpha:1.00) { didSet { updateGradient() } } @IBInspectable var cornerRadius: CGFloat = 8.0 { didSet { updateCornerRadius() } } private let gradientLayer = CAGradientLayer() override init(frame: CGRect) { super.init(frame: frame) setupGradient() } required init?(coder: NSCoder) { super.init(coder: coder) setupGradient() } override func layoutSubviews() { super.layoutSubviews() // 视图大小变化时更新渐变图层的frame gradientLayer.frame = bounds updateCornerRadius() } private func setupGradient() { gradientLayer.colors = [startColor.cgColor, endColor.cgColor] // 可以根据需求调整渐变方向,这里是左上到右下 gradientLayer.startPoint = CGPoint(x: 0, y: 0) gradientLayer.endPoint = CGPoint(x: 1, y: 1) // 把渐变图层插入到最底层,避免覆盖其他子视图 layer.insertSublayer(gradientLayer, at: 0) updateCornerRadius() } private func updateGradient() { gradientLayer.colors = [startColor.cgColor, endColor.cgColor] } private func updateCornerRadius() { // 设置View图层的圆角,并用masksToBounds裁剪子图层(包括渐变) layer.cornerRadius = cornerRadius layer.masksToBounds = true } }
扩展:添加阴影同时保留圆角
如果需要给View加阴影,masksToBounds会把阴影也裁剪掉,这时候可以用CAShapeLayer作为渐变图层的遮罩:
private func updateCornerRadius() { let maskLayer = CAShapeLayer() maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath gradientLayer.mask = maskLayer // 添加阴影配置 layer.shadowColor = UIColor.black.cgColor layer.shadowOpacity = 0.3 layer.shadowOffset = CGSize(width: 0, height: 2) layer.shadowRadius = 4 // 设置shadowPath优化阴影绘制性能 layer.shadowPath = maskLayer.path }
方案二:在draw(_ rect:)中先裁剪上下文再画渐变
如果你坚持用draw(_ rect:)的方式绘制渐变,可以先创建圆角路径并裁剪上下文,这样后续绘制的渐变就会被限制在圆角区域内:
import UIKit @IBDesignable class PlayerCellView: UIView { @IBInspectable var startColor: UIColor = UIColor(red:0.20, green:0.75, blue:1.00, alpha:1.00) { didSet { setNeedsDisplay() } } @IBInspectable var endColor: UIColor = UIColor(red:0.07, green:0.42, blue:1.00, alpha:1.00) { didSet { setNeedsDisplay() } } @IBInspectable var cornerRadius: CGFloat = 8.0 { didSet { setNeedsDisplay() } } override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } // 1. 创建圆角路径 let roundedRectPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) // 2. 裁剪上下文,后续所有绘制都会被限制在这个路径内 roundedRectPath.addClip() // 3. 绘制你的渐变内容 let colors = [startColor.cgColor, endColor.cgColor] let locations: [CGFloat] = [0.0, 1.0] guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locations) else { return } let startPoint = CGPoint(x: rect.minX, y: rect.minY) let endPoint = CGPoint(x: rect.maxX, y: rect.maxY) context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: []) } }
两种方案对比
- 方案一(图层方式):性能更优,适合需要频繁刷新或添加阴影、边框等效果的场景,是iOS开发的推荐方式。
- 方案二(drawRect方式):代码更贴近你原有的实现,但性能不如图层方案,适合简单的静态视图。
内容的提问来源于stack exchange,提问作者Frodo
相关产品推荐
相关产品推荐

