Swift UIKit中实现带底部半圆的自定义圆角矩形形状问题(含半透明背景与边框处理)
Swift UIKit中实现带底部半圆的自定义圆角矩形形状问题(含半透明背景与边框处理)
嗨,我完全懂你现在卡壳的点——要做这么个带底部左侧半圆的圆角矩形,还得兼顾半透明背景和完整的连续边框,确实容易在路径组合和绘制逻辑上踩坑。我先帮你分析下当前代码的问题,再给你个可行的解决方案。
你当前代码的核心问题
- 路径衔接断层:你设置的圆角矩形高度是
height - 8,而半圆的位置在height - 24,这导致两个形状之间有明显间隙,边框自然会断开。 - 填充叠加问题:直接把两个独立路径
append后关闭了usesEvenOddFillRule,半透明背景下重叠区域的填充会叠加,颜色会变深,视觉效果不对。 - 描边重复绘制:两个路径的边框在可能的重叠区域会重复画,导致线条变粗,破坏整体观感。
修正后的实现方案
我们需要构建一个单一的闭合连续路径,让圆角矩形和半圆无缝衔接,这样填充和描边都能一次性完成,避免叠加和断层问题。以下是调整后的代码:
override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } // 可配置参数,方便后续调整 let cornerRadius: CGFloat = 24 let semicircleRadius: CGFloat = 12 let lineWidth: CGFloat = 1 let fillColor = configuration.isTransparent ? UIColor.primaryPurple.withAlphaComponent(0.7) : UIColor.primaryPurple let strokeColor = UIColor.primaryPurple.cgColor // 圆角矩形的有效高度:留出半圆的空间(直径24) let roundedRectHeight = rect.height - semicircleRadius * 2 let roundedRectFrame = CGRect(x: 0, y: 0, width: rect.width, height: roundedRectHeight) // 构建完整的连续路径 let customPath = UIBezierPath() // 1. 左上角圆角 -> 顶部 -> 右上角圆角 let topLeftPoint = CGPoint(x: cornerRadius, y: 0) customPath.move(to: topLeftPoint) customPath.addArc( withCenter: CGPoint(x: rect.width - cornerRadius, y: cornerRadius), radius: cornerRadius, startAngle: .pi * 1.5, endAngle: 0, clockwise: true ) // 2. 右侧 -> 右下角圆角 customPath.addArc( withCenter: CGPoint(x: rect.width - cornerRadius, y: roundedRectHeight - cornerRadius), radius: cornerRadius, startAngle: 0, endAngle: .pi * 0.5, clockwise: true ) // 3. 底部右侧 -> 半圆右端点 let semicircleEndPoint = CGPoint(x: 24 + semicircleRadius, y: roundedRectHeight) customPath.addLine(to: semicircleEndPoint) // 4. 绘制底部左侧的半圆(向外突出) let semicircleCenter = CGPoint(x: 24, y: roundedRectHeight) customPath.addArc( withCenter: semicircleCenter, radius: semicircleRadius, startAngle: 0, endAngle: .pi, clockwise: false ) // 5. 半圆左端点 -> 左下角圆角 let semicircleStartPoint = CGPoint(x: 24 - semicircleRadius, y: roundedRectHeight) customPath.addLine(to: semicircleStartPoint) customPath.addArc( withCenter: CGPoint(x: cornerRadius, y: roundedRectHeight - cornerRadius), radius: cornerRadius, startAngle: .pi * 0.5, endAngle: .pi, clockwise: true ) // 6. 左侧 -> 回到起点,闭合路径 customPath.addLine(to: topLeftPoint) // 填充路径(半透明背景也不会有叠加问题) context.addPath(customPath.cgPath) context.setFillColor(fillColor.cgColor) context.fillPath() // 描边路径(连续线条,无断开或重复) context.addPath(customPath.cgPath) context.setStrokeColor(strokeColor) context.setLineWidth(lineWidth) context.setLineJoin(.round) context.strokePath() }
关键思路说明
- 连续路径构建:从头开始一步步绘制整个形状,确保圆角矩形和半圆的衔接处没有间隙,边框自然连续。
- 参数化配置:把圆角半径、半圆半径等提取成变量,后续调整形状尺寸时更方便。
- 避免填充叠加:用单一闭合路径填充,半透明背景下不会出现颜色叠加变深的问题。
- 精确角度控制:通过
addArc方法的角度参数,确保圆角和半圆的绘制方向完全匹配,视觉上更统一。
如果你的需求是半圆向内凹陷(而不是向外突出),只需要把半圆绘制的clockwise参数改成true,或者结合usesEvenOddFillRule做路径减法即可。
内容来源于stack exchange
相关产品推荐
相关产品推荐

