在UIView Swift中居中CAShapeLayer [英] Centering CAShapeLayer within UIView Swift
问题描述
我无法将CAShapeLayer集中在UIView中。我已经搜索过,大多数解决方案都是从2015年前的Obj C开始的,或者还没有解决。
I'm having trouble centering CAShapeLayer within a UIView. I've search and most solutions are from pre 2015 in Obj C or haven't been solved.
附图是图像的样子。当我检查它,它在红色视图内,但idk为什么它不居中。我已经尝试过调整它但仍然无效。
Attached is what the image looks like. When I inspect it, its inside the red view, but idk why its not centering. I've tried resizing it but still doesn't work.
let progressView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
//MARK: - ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(progressView)
progressView.anchor(top: nil, left: nil, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 200, height: 200)
progressView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
progressView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
setupCircleLayers()
}
var shapeLayer: CAShapeLayer!
private func setupCircleLayers() {
let trackLayer = createCircleShapeLayer(strokeColor: UIColor.rgb(red: 56, green: 25, blue: 49, alpha: 1), fillColor: #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1))
progressView.layer.addSublayer(trackLayer)
}
private func createCircleShapeLayer(strokeColor: UIColor, fillColor: UIColor) -> CAShapeLayer {
let centerpoint = CGPoint(x: progressView.frame.width / 2, y: progressView.frame.height / 2)
let circularPath = UIBezierPath(arcCenter: centerpoint, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
let layer = CAShapeLayer()
layer.path = circularPath.cgPath
layer.fillColor = fillColor.cgColor
layer.lineCap = kCALineCapRound
layer.position = progressView.center
return layer
}
推荐答案
正如@ukim所说,你的问题是你在根据视图及其大小确定之前确定图层的位置。
As @ukim says, your problem is that you are trying to determine the position of your layer, based on views and their size before these are finite.
当你在 viewDidLoad
时,你还不知道你的观点的大小和最终位置。您可以添加 progressView
,但在 viewDidLayoutSubviews
之前,您无法确定其大小或位置是否正确(已记录< a href =https://developer.apple.com/documentation/uikit/uiviewcontroller/1621398-viewDidlayoutsubviews =nofollow noreferrer>这里)。
When you are in viewDidLoad
you don't know the size and final position of your views yet. You can add the progressView
alright but you can not be sure that its size or position are correct until viewDidLayoutSubviews
(documented here).
因此,如果我将您的呼叫转移到 setupCircleLayers
到 viewDidLayoutSubviews
,我将中心点更改为 CGPoint.zero
并将 layer.position
的计算改为:
So, if I move your call to setupCircleLayers
to viewDidLayoutSubviews
and I change the centerpoint to CGPoint.zero
and alter the calculation of your layer.position
to this:
layer.position = CGPoint(x: progressView.frame.size.width / 2, y: progressView.frame.size.height / 2)
然后我看到:
我希望更多的是你的目标。
Which I hope is more what you were aiming for.
这是完整列表(注意我必须更改一些方法,因为我无法访问 anchor
或 UIColor.rgb $ c例如$ c>但是你可以解决这个问题:))
Here is the complete listing (note that I had to change some of your methods as I didn't have access to anchor
or UIColor.rgb
for instance but you can probably work your way around that :))
import UIKit
class ViewController: UIViewController {
var shapeLayer: CAShapeLayer!
let progressView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(progressView)
progressView.translatesAutoresizingMaskIntoConstraints = false
progressView.heightAnchor.constraint(equalToConstant: 200).isActive = true
progressView.widthAnchor.constraint(equalToConstant: 200).isActive = true
progressView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
progressView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if shouldAddSublayer {
setupCircleLayers()
}
}
private func setupCircleLayers() {
let trackLayer = createCircleShapeLayer(strokeColor: UIColor.init(red: 56/255, green: 25/255, blue: 49/255, alpha: 1), fillColor: #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1))
progressView.layer.addSublayer(trackLayer)
}
private var shouldAddSublayer: Bool {
/*
check if:
1. we have any sublayers at all, if we don't then its safe to add a new, so return true
2. if there are sublayers, see if "our" layer is there, if it is not, return true
*/
guard let sublayers = progressView.layer.sublayers else { return true }
return sublayers.filter({ $0.name == "myLayer"}).count == 0
}
private func createCircleShapeLayer(strokeColor: UIColor, fillColor: UIColor) -> CAShapeLayer {
let centerpoint = CGPoint.zero
let circularPath = UIBezierPath(arcCenter: centerpoint, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
let layer = CAShapeLayer()
layer.path = circularPath.cgPath
layer.fillColor = fillColor.cgColor
layer.lineCap = kCALineCapRound
layer.position = CGPoint(x: progressView.frame.size.width / 2, y: progressView.frame.size.height / 2)
layer.name = "myLayer"
return layer
}
}
希望有所帮助。
当您执行上述操作时,这也意味着每次 viewDidLayoutSubviews
被调用,您正在添加一个新的图层。为避免这种情况,您可以使用图层的名称
属性
When you do the above, that also means that every time viewDidLayoutSubviews
is called, you are adding a new layer. To circumvent that, you can use the name
property of a layer
layer.name = "myLayer"
然后检查您是否已添加图层。这样的事情应该有效:
and then check if you have already added your layer. Something like this should work:
private var shouldAddSublayer: Bool {
/*
check if:
1. we have any sublayers at all, if we don't then its safe to add a new, so return true
2. if there are sublayers, see if "our" layer is there, if it is not, return true
*/
guard let sublayers = progressView.layer.sublayers else { return true }
return sublayers.filter({ $0.name == "myLayer"}).count == 0
}
然后你在这里使用:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if shouldAddSublayer {
setupCircleLayers()
}
}
我已经更新了清单。
这篇关于在UIView Swift中居中CAShapeLayer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!