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

SwiftUI如何制作自定义圆角异形?现有实现复杂且圆角不完美

如何简便实现带圆角的自定义形状(SwiftUI)

自定义形状示例

我按照Apple官方的SwiftUI绘图教程实现了一个自定义形状,但当前实现过于复杂,圆角效果不够理想,而且后续维护起来很麻烦。想请教有没有更简便的实现思路?

当前实现代码

HexagonParameters 结构体

struct HexagonParameters {
    
    struct Segment {
        let line: CGPoint
        let curve: CGPoint
        let control: CGPoint
    }
    
    static let adjustment: CGFloat = 0.085
    
    static let topSholdHt = 0.13
    static let botSholdHt = 0.87
    
    static let segments = [
        
        Segment( // top center
                line:    CGPoint(x: 0.80, y: topSholdHt), // top right
                curve:   CGPoint(x: 0.20, y: topSholdHt), // top left
                control: CGPoint(x: 0.50, y: 0.00) // center / peak
            ),
            Segment( // upper left
                line:    CGPoint(x: 0.05, y: 0.20),
                curve:   CGPoint(x: 0.00, y: 0.30),
                control: CGPoint(x: 0.0, y: 0.23)
            ),
            Segment( // lower left
                line:    CGPoint(x: 0.00, y: 0.70),
                curve:   CGPoint(x: 0.05, y: 0.80),
                control: CGPoint(x: 0.00, y: 0.78)
            ),
            Segment( // bottom center
                line:    CGPoint(x: 0.20, y: botSholdHt),
                curve:   CGPoint(x: 0.80, y: botSholdHt),
                control: CGPoint(x: 0.50, y: 1.00)
            ),
            Segment(    // lower right
                line:    CGPoint(x: 0.95, y: 0.80),
                curve:   CGPoint(x: 1.00, y: 0.70),
                control: CGPoint(x: 1.00, y: 0.78)
            ),
            Segment(
                line:    CGPoint(x: 1.00, y: 0.30),
                curve:   CGPoint(x: 0.95, y: 0.20),
                control: CGPoint(x: 1.00, y: 0.23)
            )
    ]
    
}

视图中使用代码

struct ContentView: View {
    var body: some View {
        Path { path in
            var width: CGFloat = 300.0
            let height = width
            path.move(
                to: CGPoint(
                    x: width * 0.95,
                    y: height * 0.20
                )
            )
            
            HexagonParameters.segments.forEach { segment in
                path.addLine(
                    to: CGPoint(
                        x: width * segment.line.x,
                        y: height * segment.line.y
                    )
                )
                
                path.addQuadCurve(
                    to: CGPoint(
                        x: width * segment.curve.x,
                        y: height * segment.curve.y),
                    control: CGPoint(
                        x: width * segment.control.x,
                        y: height * segment.control.y
                    )
                )
            }
        }
        .stroke(style: StrokeStyle(lineWidth: 2))
        .foregroundColor(Color.black)
        .padding(.horizontal)

    }
}

更简便的实现思路

方案1:基于RoundedRectangle的裁剪与拼接

这个形状可以看作是上下扁平、左右带圆角的变体,通过基础圆角矩形结合线段拼接实现,代码简洁易维护:

struct CustomShape: Shape {
    let cornerRadius: CGFloat
    let flatRatio: CGFloat = 0.13 // 对应原实现的上下扁平高度比例
    
    func path(in rect: CGRect) -> Path {
        // 先绘制中间带左右圆角的矩形
        let middleRect = CGRect(
            x: rect.minX,
            y: rect.minY + rect.height * flatRatio,
            width: rect.width,
            height: rect.height * (1 - 2 * flatRatio)
        )
        var path = RoundedRectangle(cornerRadius: cornerRadius)
            .path(in: middleRect)
        
        // 添加顶部扁平线段
        let topLeft = CGPoint(x: rect.minX + cornerRadius, y: rect.minY)
        let topRight = CGPoint(x: rect.maxX - cornerRadius, y: rect.minY)
        path.move(to: topLeft)
        path.addLine(to: topRight)
        path.addLine(to: CGPoint(x: topRight.x, y: middleRect.minY))
        
        // 添加底部扁平线段
        let bottomLeft = CGPoint(x: rect.minX + cornerRadius, y: rect.maxY)
        let bottomRight = CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY)
        path.move(to: bottomLeft)
        path.addLine(to: bottomRight)
        path.addLine(to: CGPoint(x: bottomRight.x, y: middleRect.maxY))
        
        return path
    }
}

// 使用示例
struct ContentView: View {
    var body: some View {
        CustomShape(cornerRadius: 30)
            .stroke(style: StrokeStyle(lineWidth: 2))
            .foregroundColor(.black)
            .frame(width: 300, height: 300)
            .padding(.horizontal)
    }
}

方案2:直接用Path绘制标准化路径

放弃复杂的分段结构,按顺序绘制关键点,用addArc实现标准平滑圆角,可读性和维护性更强:

struct CustomShape: Shape {
    func path(in rect: CGRect) -> Path {
        let cornerRadius: CGFloat = 30
        let flatOffset = rect.height * 0.13
        
        var path = Path()
        
        // 顶部右侧起点
        let topRightStart = CGPoint(x: rect.maxX - cornerRadius, y: flatOffset)
        path.move(to: topRightStart)
        
        // 顶部扁平线
        path.addLine(to: CGPoint(x: rect.minX + cornerRadius, y: flatOffset))
        
        // 左上圆角
        path.addArc(
            center: CGPoint(x: rect.minX + cornerRadius, y: flatOffset + cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(270),
            endAngle: .degrees(180),
            clockwise: false
        )
        
        // 左侧竖线
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY - flatOffset - cornerRadius))
        
        // 左下圆角
        path.addArc(
            center: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY - flatOffset - cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(180),
            endAngle: .degrees(90),
            clockwise: false
        )
        
        // 底部扁平线
        path.addLine(to: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - flatOffset))
        
        // 右下圆角
        path.addArc(
            center: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - flatOffset - cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(90),
            endAngle: .degrees(0),
            clockwise: false
        )
        
        // 右侧竖线
        path.addLine(to: CGPoint(x: rect.maxX, y: flatOffset + cornerRadius))
        
        // 右上圆角
        path.addArc(
            center: CGPoint(x: rect.maxX - cornerRadius, y: flatOffset + cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(0),
            endAngle: .degrees(270),
            clockwise: false
        )
        
        return path
    }
}

// 使用示例
struct ContentView: View {
    var body: some View {
        CustomShape()
            .stroke(style: StrokeStyle(lineWidth: 2))
            .foregroundColor(.black)
            .frame(width: 300, height: 300)
            .padding(.horizontal)
    }
}

方案优势

  • 代码结构清晰,调整圆角大小、上下扁平比例只需修改几个常量
  • 用addArc实现的圆角更标准平滑,避免手动计算贝塞尔曲线控制点的误差
  • 符合SwiftUI的Shape协议规范,可直接复用、自适应尺寸

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 12:45:54