[英]Centering CAShapeLayer within UIView Swift
我在UIView中將CAShapeLayer居中時遇到麻煩。 我已經搜索過,大多數解決方案來自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
到viewDidLayoutSubviews
和我變更中心點到CGPoint.zero
和改變你的計算layer.position
這樣:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.