在UIView Swift中居中CAShapeLayer [英] Centering CAShapeLayer within UIView Swift

查看:175
本文介绍了在UIView Swift中居中CAShapeLayer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法将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 但是你可以解决这个问题:))

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆