You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS开发:如何实现各边角半径不同的带阴影Card View?

实现四个边角半径各不相同的Card View

你遇到的问题很常见——UIBezierPath(roundedRect:byRoundingCorners:cornerRadii:)这个方法只能给一组边角设置相同的半径,没法单独给四个角指定不同的值,所以你之前的代码只改了一个角,效果自然不对。要实现四个角各不同的圆角,我们需要手动构建完整的贝塞尔路径,同时还要保证阴影能正确匹配这个自定义圆角路径。

下面是完整的解决方案,我把四个角的半径都做成@IBInspectable属性,这样你可以直接在Storyboard里可视化调整每个角的数值:

import UIKit

class CustomCornerCard: UIView {
    // 四个角的独立半径,支持IB可视化编辑
    @IBInspectable var topLeftRadius: CGFloat = 0
    @IBInspectable var topRightRadius: CGFloat = 0
    @IBInspectable var bottomLeftRadius: CGFloat = 0
    @IBInspectable var bottomRightRadius: CGFloat = 0
    
    // 阴影相关属性,保留你原来的配置
    @IBInspectable var shadowOffsetWidth: Int = 0
    @IBInspectable var shadowOffsetHeight: Int = 3
    @IBInspectable var shadowColor: UIColor? = .gray
    @IBInspectable var shadowOpacity: Float = 0.5
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // 1. 创建自定义圆角路径
        let path = UIBezierPath()
        let bounds = self.bounds
        
        // 从右上圆角的起点开始(顺时针绘制)
        path.move(to: CGPoint(x: bounds.maxX - topRightRadius, y: bounds.minY))
        
        // 右上圆角
        path.addArc(withCenter: CGPoint(x: bounds.maxX - topRightRadius, y: bounds.minY + topRightRadius),
                    radius: topRightRadius,
                    startAngle: CGFloat(3 * .pi / 2),
                    endAngle: 0,
                    clockwise: true)
        
        // 右边缘
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY - bottomRightRadius))
        
        // 右下圆角
        path.addArc(withCenter: CGPoint(x: bounds.maxX - bottomRightRadius, y: bounds.maxY - bottomRightRadius),
                    radius: bottomRightRadius,
                    startAngle: 0,
                    endAngle: CGFloat(.pi / 2),
                    clockwise: true)
        
        // 下边缘
        path.addLine(to: CGPoint(x: bounds.minX + bottomLeftRadius, y: bounds.maxY))
        
        // 左下圆角
        path.addArc(withCenter: CGPoint(x: bounds.minX + bottomLeftRadius, y: bounds.maxY - bottomLeftRadius),
                    radius: bottomLeftRadius,
                    startAngle: CGFloat(.pi / 2),
                    endAngle: CGFloat(.pi),
                    clockwise: true)
        
        // 左边缘
        path.addLine(to: CGPoint(x: bounds.minX, y: bounds.minY + topLeftRadius))
        
        // 左上圆角
        path.addArc(withCenter: CGPoint(x: bounds.minX + topLeftRadius, y: bounds.minY + topLeftRadius),
                    radius: topLeftRadius,
                    startAngle: CGFloat(.pi),
                    endAngle: CGFloat(3 * .pi / 2),
                    clockwise: true)
        
        // 闭合路径
        path.close()
        
        // 2. 设置圆角遮罩
        let maskLayer = CAShapeLayer()
        maskLayer.path = path.cgPath
        self.layer.mask = maskLayer
        
        // 3. 设置阴影,确保阴影路径和圆角路径一致
        self.layer.masksToBounds = false
        self.layer.shadowColor = shadowColor?.cgColor
        self.layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
        self.layer.shadowOpacity = shadowOpacity
        self.layer.shadowPath = path.cgPath
    }
}

关键说明:

  • 手动构建路径:通过addArc方法分别给四个角绘制不同半径的圆弧,再用addLine连接各边,确保路径完全匹配你想要的圆角效果。
  • 遮罩与阴影同步:把同一个路径同时作为layer.mask(实现圆角)和layer.shadowPath(实现和圆角完全贴合的阴影),这样阴影不会出现“漏角”或者形状不符的问题。
  • IBInspectable支持:四个角的半径都可以在Storyboard的Attributes Inspector里直接修改,实时预览效果,不用每次改代码。

使用方法:

  1. 把这段代码添加到你的项目中
  2. 在Storyboard里把你的View的Class改成CustomCornerCard
  3. 在Attributes面板里找到对应的四个圆角属性,分别设置你需要的数值(比如左上5、左下10、右上20、右下30)
  4. 调整阴影属性到你想要的效果

这样就能实现你预期的四个角不同半径的Card View了,阴影也会完美贴合圆角形状。

内容的提问来源于stack exchange,提问作者Nikesh Hyanju

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:56:45