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
相关产品推荐
相关产品推荐

