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

图层的图纸效果很好,但我只是无法让他们根据视图的位置来调整其位置,该视图是使用自动布局设置的,其中视图是在代码中创建的(无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语句,以确保它们被调用并且可以正常工作。

这是我所看到的:
ios - CALayer自动版式-LMLPHP

提前致谢。

最佳答案

您需要提供以下正确的arcCenter,而无需为frame设置shapLayer

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
}

结果

ios - CALayer自动版式-LMLPHP

注意:我使用了第一个ProgressView类,而没有 KVO

09-30 11:55