CALayer Auto Layout - PullRequest
       11

CALayer Auto Layout

0 голосов
/ 05 ноября 2018

Я пытаюсь создать 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, где я ожидаю, что два слоя будут внутри.

Я продолжаю смотреть на это и думаю, что есть что-то простое, что я упускаю или делаю неправильно, и я просто не вижу этого.

Я поместил оператор print в observeValue, а также layoutSubviews, чтобы убедиться, что они вызывались и это работало.

Вот что я вижу: enter image description here

Спасибо заранее.

1 Ответ

0 голосов
/ 05 ноября 2018

Вам необходимо указать правильное значение 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
}

Результат

enter image description here

Примечание: Я использовал первый ProgressView класс без КВО .

...