CALayer 自动布局

CALayer Auto Layout

我正在尝试创建 2 个层,它们相互堆叠并且位于自定义视图内 class。

图层的绘图效果很好,但我无法让它们根据使用自动布局设置的视图位置调整它们的位置,其中视图是在代码中创建的(无 IB) .

我尝试通过调用 layoutSubviews 来更改图层的框架,这是尝试的代码。

import UIKit

class ProgressView: UIView {

    let displayLayer:  CAShapeLayer = {
        let display = CAShapeLayer()
        display.strokeColor = UIColor.red.cgColor
        display.lineWidth = 8.0
        display.lineCap = CAShapeLayerLineCap.round
        display.fillColor = UIColor.clear.cgColor
        display.strokeEnd = 0.5

        return display
    }()

    let trackLayer: CAShapeLayer = {
        let track = CAShapeLayer()

        track.strokeColor = UIColor.lightGray.cgColor
        track.lineWidth = 6.0
        track.lineCap = CAShapeLayerLineCap.round
        track.fillColor = UIColor.clear.cgColor

        return track
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        let progressCircle = UIBezierPath(arcCenter: .zero, radius: 50, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)

        displayLayer.path = progressCircle.cgPath
        trackLayer.path = progressCircle.cgPath

        layer.addSublayer(trackLayer)
        layer.addSublayer(displayLayer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        displayLayer.frame = bounds
        trackLayer.frame = bounds
    }
}

经过一些研究,我也尝试了 KVO 方法并使用了以下代码:

import UIKit

class ProgressView: UIView {
    let displayLayer:  CAShapeLayer = {
        let display = CAShapeLayer()

        display.strokeColor = UIColor.red.cgColor
        display.lineWidth = 8.0
        display.lineCap = CAShapeLayerLineCap.round
        display.fillColor = UIColor.clear.cgColor
        display.strokeEnd = 0.5

        return display
    }()

    let trackLayer: CAShapeLayer = {
        let track = CAShapeLayer()

        track.strokeColor = UIColor.lightGray.cgColor
        track.lineWidth = 6.0
        track.lineCap = CAShapeLayerLineCap.round
        track.fillColor = UIColor.clear.cgColor

        return track
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        let progressCircle = UIBezierPath(arcCenter: .zero, radius: 50, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)

        displayLayer.path = progressCircle.cgPath
        trackLayer.path = progressCircle.cgPath

        layer.addSublayer(trackLayer)
        layer.addSublayer(displayLayer)

        self.addObserver(self, forKeyPath: #keyPath(ProgressView.bounds), options: .new, context: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == #keyPath(ProgressView.bounds) {
            displayLayer.frame = self.bounds
            trackLayer.frame = self.bounds
        }
    }
}

对于每个示例,我都得到相同的结果,显示如下。请注意,紫色框是 ProgressView,我希望这两层位于其中。

我一直在看这个,并认为我缺少或做错了一些简单的事情,但我看不到它。

我在 observeValuelayoutSubviews 中都添加了 print 语句,以确保它们被调用并且有效。

这是我看到的:

提前致谢。

您需要提供正确的 arcCenter 如下,无需为 shapLayer.

设置 frame
override func layoutSubviews() {
    super.layoutSubviews()

    let center = CGPoint(x: bounds.midX, y: bounds.midY)
    let progressCircle = UIBezierPath(arcCenter: center, radius: 50, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)

    displayLayer.path = progressCircle.cgPath
    trackLayer.path = progressCircle.cgPath
}

结果

注:我用的第一个ProgressViewclass没有KVO.