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

iOS UIKit中如何用Bezier Path实现左侧内凹曲线?

解决UIKit中左侧内凹曲线的实现问题

你的问题在于用了两个独立的CAShapeLayer分别绘制左侧圆形和右侧弧形,导致形状重叠、描边重复,且左侧内凹用贝塞尔曲线(addCurve)难以精确控制弧度。正确的做法是将整个形状合并为一个闭合的UIBezierPath,用反向圆弧实现左侧内凹,只用一个图层渲染即可。

修改后的完整代码

class ArcView : UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    func setupViewWith(textToDisplay: String, imageNamed: String, backgroundColor: UIColor){
        setupView(backgroundColor: backgroundColor)
    }
    
    func setupView(backgroundColor: UIColor){
        // 用单一图层绘制完整路径
        let fullPath = getFullPath()
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = fullPath.cgPath
        shapeLayer.lineWidth = 1.5
        shapeLayer.strokeColor = UIColor.white.cgColor
        shapeLayer.fillColor = backgroundColor.cgColor
        self.layer.addSublayer(shapeLayer)
    }
    
    // 生成完整的闭合路径:左侧内凹圆弧 + 右侧外凸圆弧 + 直线连接
    func getFullPath() -> UIBezierPath {
        let height = bounds.height
        let width = bounds.width
        let halfHeight = height / 2.0
        
        // 左侧内凹圆弧参数:圆心在view垂直中线、左侧边缘外(半径等于半高)
        let leftArcCenter = CGPoint(x: halfHeight, y: halfHeight)
        let leftArcRadius = halfHeight
        
        // 右侧外凸圆弧参数:和你原来的逻辑一致
        let rightArcCenter = CGPoint(x: width - halfHeight, y: halfHeight)
        let rightArcRadius = halfHeight
        
        let path = UIBezierPath()
        
        // 起点:左侧内凹圆弧的顶部端点
        let leftTopPoint = CGPoint(x: leftArcCenter.x + leftArcRadius, y: 0)
        path.move(to: leftTopPoint)
        
        // 画直线到右侧外凸圆弧的顶部端点
        let rightTopPoint = CGPoint(x: rightArcCenter.x - rightArcRadius, y: 0)
        path.addLine(to: rightTopPoint)
        
        // 绘制右侧外凸圆弧(顺时针从顶部到底部)
        path.addArc(withCenter: rightArcCenter,
                    radius: rightArcRadius,
                    startAngle: .pi * 1.5,
                    endAngle: .pi * 0.5,
                    clockwise: true)
        
        // 画直线到左侧内凹圆弧的底部端点
        let leftBottomPoint = CGPoint(x: leftArcCenter.x + leftArcRadius, y: height)
        path.addLine(to: leftBottomPoint)
        
        // 绘制左侧内凹圆弧(逆时针从底部到顶部,形成内凹效果)
        path.addArc(withCenter: leftArcCenter,
                    radius: leftArcRadius,
                    startAngle: .pi * 0.5,
                    endAngle: .pi * 1.5,
                    clockwise: false)
        
        path.close()
        return path
    }
}

extension CGFloat {
    func toRadians() -> CGFloat {
        return self * CGFloat(Double.pi) / 180.0
    }
}

关键修改说明

  1. 合并路径:把原来的两个独立路径合并为一个闭合路径,避免图层重叠导致的视觉错误
  2. 内凹圆弧实现:用addArc并设置clockwise: false,从底部逆时针绘制到顶部,形成精准的内凹弧度,替代原来难以控制的贝塞尔曲线
  3. 使用bounds:改用self.bounds获取尺寸,适配布局变化时的视图大小调整
  4. 单一图层:只用一个CAShapeLayer渲染,保证描边连续、填充统一

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 22:38:27