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

如何在Swift中使用AutoLayout绘制四分之一圆(象限圆)

在Swift中用AutoLayout实现四分之一象限圆

核心思路

要实现标准的四分之一圆,关键是确保承载图形的视图为正方形(通过AutoLayout约束宽高相等),再用UIBezierPath绘制对应象限的圆弧并闭合路径,最后通过自定义View绘制或给普通View添加CAShapeLayer蒙版来呈现效果。

实现方案(两种常用方式)

方式一:自定义View直接绘制

创建自定义UIView子类,在绘制方法中生成对应象限的路径,同时通过AutoLayout约束宽高一致。

import UIKit

class QuarterCircleView: UIView {
    // 定义四象限枚举
    enum Quadrant {
        case topLeft, topRight, bottomLeft, bottomRight
    }
    
    var quadrant: Quadrant = .topRight {
        didSet { setNeedsDisplay() }
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        // 强制转为正方形,确保圆弧为标准四分之一圆
        let squareRect = CGRect(x: rect.origin.x, y: rect.origin.y, 
                                width: min(rect.width, rect.height), 
                                height: min(rect.width, rect.height))
        
        // 根据象限设置圆弧的起始/结束角度、圆心
        var startAngle: CGFloat = 0
        var endAngle: CGFloat = 0
        var centerPoint: CGPoint = .zero
        
        switch quadrant {
        case .topRight:
            startAngle = -CGFloat.pi / 2
            endAngle = 0
            centerPoint = CGPoint(x: squareRect.minX, y: squareRect.minY)
        case .topLeft:
            startAngle = CGFloat.pi
            endAngle = CGFloat.pi / 2
            centerPoint = CGPoint(x: squareRect.maxX, y: squareRect.minY)
        case .bottomLeft:
            startAngle = CGFloat.pi / 2
            endAngle = 0
            centerPoint = CGPoint(x: squareRect.maxX, y: squareRect.maxY)
        case .bottomRight:
            startAngle = 0
            endAngle = -CGFloat.pi / 2
            centerPoint = CGPoint(x: squareRect.minX, y: squareRect.maxY)
        }
        
        // 创建贝塞尔路径并闭合
        let path = UIBezierPath(arcCenter: centerPoint,
                                radius: squareRect.width / 2,
                                startAngle: startAngle,
                                endAngle: endAngle,
                                clockwise: true)
        path.addLine(to: centerPoint)
        path.close()
        
        // 设置填充与边框样式
        UIColor.blue.setFill()
        path.fill()
        
        UIColor.black.setStroke()
        path.lineWidth = 2
        path.stroke()
    }
    
    // 设置默认 intrinsic 大小,可被AutoLayout覆盖
    override var intrinsicContentSize: CGSize {
        return CGSize(width: 100, height: 100)
    }
}

在ViewController中添加并约束:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let quarterCircle = QuarterCircleView()
        quarterCircle.quadrant = .topRight
        quarterCircle.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(quarterCircle)
        
        // 约束:距离右上角各20pt,宽高150pt(强制宽高相等)
        NSLayoutConstraint.activate([
            quarterCircle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            quarterCircle.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            quarterCircle.widthAnchor.constraint(equalToConstant: 150),
            quarterCircle.heightAnchor.constraint(equalTo: quarterCircle.widthAnchor)
        ])
    }
}

方式二:用CAShapeLayer做蒙版

如果不想自定义View,可给普通UIView添加蒙版层实现效果,同样需要约束宽高相等:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let circleView = UIView()
        circleView.backgroundColor = .red
        circleView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(circleView)
        
        // 约束:居中显示,宽高200pt且相等
        NSLayoutConstraint.activate([
            circleView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            circleView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            circleView.widthAnchor.constraint(equalToConstant: 200),
            circleView.heightAnchor.constraint(equalTo: circleView.widthAnchor)
        ])
        
        // 布局完成后更新蒙版路径(AutoLayout会在viewDidLoad后确定bounds)
        DispatchQueue.main.async { [weak self] in
            self?.updateQuarterCircleMask(for: circleView, quadrant: .bottomLeft)
        }
    }
    
    private func updateQuarterCircleMask(for view: UIView, quadrant: QuarterCircleView.Quadrant) {
        let radius = view.bounds.width / 2
        var centerPoint: CGPoint = .zero
        var startAngle: CGFloat = 0
        var endAngle: CGFloat = 0
        
        switch quadrant {
        case .bottomLeft:
            centerPoint = CGPoint(x: view.bounds.maxX, y: view.bounds.maxY)
            startAngle = .pi/2
            endAngle = .pi
        // 可添加其他象限的配置逻辑
        default: break
        }
        
        let path = UIBezierPath()
        path.move(to: centerPoint)
        path.addArc(withCenter: centerPoint, radius: radius, 
                    startAngle: startAngle, endAngle: endAngle, clockwise: true)
        path.close()
        
        let maskLayer = CAShapeLayer()
        maskLayer.path = path.cgPath
        view.layer.mask = maskLayer
    }
}

关键注意事项

  • 强制宽高相等:只有视图为正方形时,圆弧半径才能与边长匹配,得到标准四分之一圆,可通过heightAnchor.constraint(equalTo: widthAnchor)约束。
  • 象限对应参数匹配:不同象限的圆心位置、起始/结束角度不同,需严格对应(比如右上象限圆心在视图左上角,角度范围是-π/2到0)。
  • 布局完成后更新路径:AutoLayout会在viewDidLoad之后确定视图的实际尺寸,因此需要在viewDidLayoutSubviews或异步回调中更新路径。

内容的提问来源于stack exchange,提问作者K. Janjuha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 19:01:09