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
相关产品推荐
相关产品推荐

