CAShapeLayer偏离中心

问题描述

我一直在尝试为我的应用使用UIControl创建一个自定义的“滑块”或旋钮。我找到了this教程,并一直在使用它来获得一些启发,但是由于它并没有真正完成我想做的事情,因此我将它更多地用作参考而非教程。无论如何,我写了下面的代码,发现我的CAShapeLayer不在我设置为自定义CircularSelector的实例的UIView的中心。

这是我的代码

    class CircularSelector: UIControl {
     
     
     private let renderer = CircularSelectorRenderer()
     
     override init(frame: CGRect) {
       super.init(frame: frame)
       commonInit()
     }
     
     required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
       commonInit()
     }
     
     private func commonInit() {
         
         renderer.updateBounds(bounds)
         //layer.borderWidth = 4
        // layer.borderColor = UIColor.red.cgColor
         layer.addSublayer(renderer.selectorLayer)
     }
     
 }


 class CircularSelectorRenderer {
     
     
     let selectorLayer = CAShapeLayer()
     
     init() {
         selectorLayer.fillColor = UIColor.clear.cgColor
         selectorLayer.strokeColor = UIColor.white.cgColor
         //Testing
         //selectorLayer.borderColor = UIColor.white.cgColor
        // selectorLayer.borderWidth = 4
         
     }
     
     private func updateSelectorLayerPath() {
         let bounds = selectorLayer.bounds
         let arcCenter = CGPoint(x: bounds.midX,y: bounds.maxY)
         let radius = 125
         
         var ring = UIBezierPath(arcCenter: arcCenter,radius: CGFloat(radius),startAngle: 0.degreesToradians,endAngle: 180.degreesToradians,clockwise: false)
         
         selectorLayer.linewidth = 10
         selectorLayer.path = ring.cgPath
         
     }
     
     func updateBounds(_ bounds: CGRect) {
         selectorLayer.bounds = bounds
         selectorLayer.position = CGPoint(x: bounds.midX,y: bounds.midY)
         updateSelectorLayerPath()
         
     }
     
 }

这就是我得到的:

Simulator

当我在//Testing的{​​{1}}的{​​{1}}行下取消注释代码时,我得到了:

Simulator

灰色的UIView属于init()类。对于我的CircularSelectorRenderer为什么比灰度视图本身宽,以及为什么它不在灰度视图的中央,我感到困惑。为什么会发生这种情况,我该如何解决

解决方法

问题是您在错误的位置更新了形状。视图可以(并且将)更改不同设备大小,超级视图大小,设备旋转等的大小。

当您告诉视图布局其子视图时,您想更新形状层:

class CircularSelector: UIControl {
    
    private let renderer = CircularSelectorRenderer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    private func commonInit() {
        
        // no need to call this here
        //renderer.updateBounds(bounds)
        
        //layer.borderWidth = 4
        // layer.borderColor = UIColor.red.cgColor
        
        layer.addSublayer(renderer.selectorLayer)
    }

    // add this func
    override func layoutSubviews() {
        super.layoutSubviews()

        // here is where you want to update the layer
        renderer.updateBounds(bounds)
    }

}