CAShapeLayer 偏离中心

Posted

技术标签:

【中文标题】CAShapeLayer 偏离中心【英文标题】:CAShapeLayer is off center 【发布时间】:2020-08-12 17:45:42 【问题描述】:

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

这是我的代码:

    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()
         
     
     
 

这是我得到的:

当我取消注释CircularSelectorRendererinit()//Testing 行下的代码时,我得到了这个:

灰色的 UIView 属于 CircularSelector 类。我很困惑为什么我的CAShapeLayer 比灰色视图本身更宽,为什么它不在灰色视图的中心。为什么会发生这种情况,我该如何解决。

【问题讨论】:

你在哪里设置灰色背景的框架? 您是否尝试在故事板中为视图设置固定宽度或在自定义视图的layoutSubviews 中调用updateBounds(_ bounds: CGRect) 我在情节提要中创建了 UIView,并将前导和尾随约束设置为 20,我将底部设置为与安全区域对齐,并将高度约束设置为 150。跨度> 我刚刚尝试调用 updateBounds 函数添加到 layoutSubviews 函数中(我的自定义类没有它,所以我必须添加它),它似乎工作!现在我很困惑,因为在我用作参考的教程中不需要 layoutSubview 函数,并且 CAShapeLayer 似乎很好地显示在中心。我想知道我做了什么不同的事情导致了这个问题,以及我是否会遇到任何意想不到的问题。如果它有任何可预测的副作用,你知道它为什么会起作用吗? @Jithin 另外,如果你有时间,我很想知道我在做什么与教程不同。 【参考方案1】:

问题是您在错误的位置更新形状。视图可以(并且将会)根据不同的设备尺寸、超级视图尺寸、设备旋转等改变尺寸。

当您的视图被告知布局其子视图时,您希望更新形状层:

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)
    


【讨论】:

以上是关于CAShapeLayer 偏离中心的主要内容,如果未能解决你的问题,请参考以下文章

文字稍微偏离中心

UITabBar 图标在 iPad 上偏离中心

通过 UIElement.TranslatePoint 计算子元素中心偏离正确值

为啥这个基本菜单列表偏离中心并且与它下面的文本不对齐?

在 Java 中使用 GridBagLayout 时防止 Swing 组件偏离中心

为啥我在 Swing 的 JButton 中的 html 代码偏离中心?