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()
这是我得到的:
当我取消注释CircularSelectorRenderer
的init()
中//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 偏离中心的主要内容,如果未能解决你的问题,请参考以下文章
通过 UIElement.TranslatePoint 计算子元素中心偏离正确值