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

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()
}

关键思路说明

  1. 连续路径构建:从头开始一步步绘制整个形状,确保圆角矩形和半圆的衔接处没有间隙,边框自然连续。
  2. 参数化配置:把圆角半径、半圆半径等提取成变量,后续调整形状尺寸时更方便。
  3. 避免填充叠加:用单一闭合路径填充,半透明背景下不会出现颜色叠加变深的问题。
  4. 精确角度控制:通过addArc方法的角度参数,确保圆角和半圆的绘制方向完全匹配,视觉上更统一。

如果你的需求是半圆向内凹陷(而不是向外突出),只需要把半圆绘制的clockwise参数改成true,或者结合usesEvenOddFillRule做路径减法即可。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:23:01