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

UIView中绘制的圆未居中问题技术求助

问题出在坐标系搞混啦!我来帮你搞定

你遇到的这个问题,核心是坐标系的概念搞混了:

  • self.center是当前CircleView在父视图坐标系里的中心点位置
  • 但UIBezierPath的arcCenter参数需要的是当前视图自身坐标系内的坐标

所以你用self.center当圆心,相当于把圆的中心定位到了父视图里的那个点,而绘制是在当前视图的bounds范围内进行的,自然就跑到右下角去了~

第一步:修正圆心坐标

把圆心改成当前视图自身bounds的中心就好,直接用bounds.midX和bounds.midY:

let circularPath = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), 
                                radius: 100, 
                                startAngle: -CGFloat.pi / 2, 
                                endAngle: 2 * CGFloat.pi, 
                                clockwise: true)

第二步:优化代码(避免重复操作坑)

另外注意:你的draw(_ rect:)方法会被系统多次调用(比如视图大小变化、重绘时),每次调用都添加shapeLayer和手势识别器,会导致重复添加一堆子layer和手势,不仅浪费性能,还可能出奇怪的问题。

应该把这些初始化配置移到视图的初始化方法里,只执行一次:

class CircleView: UIView { 
    let shapeLayer = CAShapeLayer() 

    // 适配代码创建和Storyboard/XIB创建两种场景
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupInitialConfig()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupInitialConfig()
    }

    // 把初始化配置抽到单独方法里,代码更清晰
    private func setupInitialConfig() {
        // 配置shapeLayer的样式
        shapeLayer.strokeColor = Colors.darkPurple.cgColor 
        shapeLayer.fillColor = UIColor.white.cgColor 
        shapeLayer.lineWidth = 10 
        shapeLayer.strokeEnd = 0 
        layer.addSublayer(shapeLayer)
        
        // 添加手势识别器
        addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
    }

    override func draw(_ rect: CGRect) { 
        // 每次重绘时更新路径(比如视图大小变了,圆心和半径也能跟着调整)
        let circularPath = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), 
                                        radius: 100, 
                                        startAngle: -CGFloat.pi / 2, 
                                        endAngle: 2 * CGFloat.pi, 
                                        clockwise: true) 
        shapeLayer.path = circularPath.cgPath 
    } 

    @objc private func handleTap() { 
        print("....Animating Circle....") 
        let basicAnimation = CABasicAnimation(keyPath: "strokeEnd") 
        basicAnimation.toValue = 1 
        basicAnimation.duration = 2 
        basicAnimation.fillMode = .forwards 
        basicAnimation.isRemovedOnCompletion = false 
        shapeLayer.add(basicAnimation, forKey: "circleAnimation") 
    } 
}

额外小建议

如果你的CircleView可能会自适应布局(比如屏幕旋转、尺寸变化),可以让半径也自适应,比如改成:

let radius = min(bounds.width, bounds.height)/2 - shapeLayer.lineWidth/2

这样圆始终会在视图内部,不会超出边界~

内容的提问来源于stack exchange,提问作者Jonas Gamburg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 15:32:55