在UIView Swift中居中CAShapeLayer
我很难将CAShapeLayer集中在UIView中。 我已经搜索过,大多数解决方案都是从2015年前的Obj C开始的,或者还没有解决。
附件是图像的样子。 当我检查它,它在红色视图内,但idk为什么它不居中。 我已经尝试过调整它但仍然无法正常工作。
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所说,你的问题在于你在确定图层的位置之前,根据视图及其大小确定图层的位置是有限的。
当您在viewDidLoad
您还不知道视图的大小和最终位置。 您可以添加progressView
但在viewDidLayoutSubviews
( 此处记录 )之前,您无法确定其大小或位置是否正确。
因此,如果我将您对setupCircleLayers
的调用setupCircleLayers
viewDidLayoutSubviews
并将中心点更改为CGPoint.zero
并将CGPoint.zero
的计算更改为:
layer.position = CGPoint(x: progressView.frame.size.width / 2, y: progressView.frame.size.height / 2)
然后我看到了这个:
我希望更多的是你的目标。
这是完整的列表(注意我必须更改你的一些方法,因为我没有访问anchor
或UIColor.rgb
,但你可以解决这个问题:))
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
,您都要添加一个新图层。 为了避免这种情况,您可以使用图层的name
属性
layer.name = "myLayer"
然后检查您是否已添加图层。 像这样的东西应该工作:
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() } }
我已经更新了这个列表。
您正在viewDidLoad()
中调用setupCircleLayers()
viewDidLoad()
。 当时尚未根据约束计算progressView.frame
。
尝试
let centerpoint = CGPoint(x: 100, y: 100)
而不是从progressView.frame
计算值
您可以在游乐场尝试:
import UIKit import PlaygroundSupport class MyVC: UIViewController { let progressView: UIView = { let view = UIView() view.backgroundColor = .red return view }() var layer: CAShapeLayer? override func viewDidLoad() { super.viewDidLoad() view.addSubview(progressView) progressView.translatesAutoresizingMaskIntoConstraints = false progressView.backgroundColor = .red progressView.widthAnchor.constraint(equalToConstant: 200).isActive = true progressView.heightAnchor.constraint(equalToConstant: 200).isActive = true 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: .red, 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: 100, y: 100) 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 return layer } } let containerView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 375.0, height: 667.0)) let vc = MyVC() PlaygroundPage.current.liveView = vc.view