Init 与layoutSubviews 中配置标签和循环进度条

问题描述 投票:0回答:1

我正在开发一个速度测试应用程序,它有一个自定义

CircularProgressView
,其中包括
speedLabel
,并且
speedLabel
位于进度视图的中心。

我有一个

createCircularPath
方法来创建进度视图的路径,我在
layoutSubviews
内部调用它。

当我在自定义视图的

speedLabel
中配置
init
并运行速度测试时,
speedLabel
文本和
progressTrack
将在测试运行时按预期更新。但是,如果我将
speedLabel
中的
layoutSubviews
与圆形路径一起配置,那么它们都不会被更新。

我尝试通过更改 z 分数来玩它。我还尝试将圆形路径、progressLayer 和 trackLayer 嵌入到另一个视图中,然后将视图和标签添加为子视图,但在

layoutSubviews
内配置时,进度和速度在速度测试期间仍然没有更新。

寻求解释为什么会这样。

工作进度的屏幕截图(当在

speedLabel
中配置
init
时): enter image description here enter image description here

当在

speedLabel
中配置
layoutSubviews
时,标签和进度保持静态。下面是在
layoutSubviews

中配置时的代码
import UIKit

class CircularProgressView: UIView {
    
    var progressLayer = CAShapeLayer()
    var trackLayer = CAShapeLayer()
    var speedLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        createCircularPath()
        configureSpeedLabel()
    }
    
    var progressColor = UIColor.white {
        didSet {
            progressLayer.strokeColor = progressColor.cgColor
        }
    }
    
    var trackColor = UIColor.white {
        didSet {
            trackLayer.strokeColor = trackColor.cgColor
        }
    }
    
    var speed = 0 {
        didSet {
            speedLabel.text = String(speed)
        }
    }
    
    fileprivate func configureSpeedLabel() {
        speedLabel.translatesAutoresizingMaskIntoConstraints = false
        speedLabel.text = String(speed)
        speedLabel.font = UIFont(name: "TimesNewRomanPSMT", size: 24)
        speedLabel.textColor = UIColor.black
        speedLabel.isOpaque = true
        self.addSubview(speedLabel)
        NSLayoutConstraint.activate([
            speedLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor),
            speedLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor)
        ])
    }
    fileprivate func createCircularPath() {
        self.backgroundColor = UIColor.clear
        self.layer.cornerRadius = self.frame.width/2
        let path = UIBezierPath(arcCenter: CGPoint(x: frame.width/2, y: frame.height/2), radius: (frame.width - 1.5)/2, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(1.5 * .pi), clockwise: true)
        trackLayer.path = path.cgPath
        trackLayer.fillColor = UIColor.clear.cgColor
        trackLayer.strokeColor = trackColor.cgColor
        trackLayer.opacity = 0.3
        trackLayer.lineWidth = 10.0
        trackLayer.strokeEnd = 1.0
        self.layer.addSublayer(trackLayer)

        progressLayer.path = path.cgPath
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.strokeColor = progressColor.cgColor
        progressLayer.lineWidth = 10.0
        progressLayer.strokeEnd = 0.0
        self.layer.addSublayer(progressLayer)
    }

}
ios swift uiview layoutsubviews
1个回答
0
投票

layoutSubviews()
添加子视图和图层是一个非常糟糕的主意。

当我们初始化视图时,我们要配置标签属性并将其添加为子视图,并配置图层属性并将它们添加为子图层。

然后,在

layoutSubviews()
中,我们知道了视图的框架(如果框架发生变化,它将再次调用),我们可以定义路径和视图的角半径。

然后在“可设置”属性(颜色、速度等)中,我们只需要更新相关元素属性即可。

快速修改您的课程...


CircularProgressView类

class CircularProgressView: UIView {
    
    var progressLayer = CAShapeLayer()
    var trackLayer = CAShapeLayer()
    var speedLabel = UILabel()
    
    var progressColor = UIColor.white {
        didSet {
            progressLayer.strokeColor = progressColor.cgColor
        }
    }
    
    var trackColor = UIColor.white {
        didSet {
            trackLayer.strokeColor = trackColor.cgColor
        }
    }
    
    // assuming we are setting the speed to an Int value
    //  between 0 and 100
    var speed: Int = 0 {
        didSet {
            // don't exceed 100
            let spd: Int = min(speed, 100)
            speedLabel.text = String(spd)
            progressLayer.strokeEnd = CGFloat(spd) / 100.0
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() {
        createCircularPath()
        configureSpeedLabel()
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // this is where we know the frame of the view (self)
        // so here we can define the corner radius and the path
        self.layer.cornerRadius = self.frame.width/2
        let path = UIBezierPath(arcCenter: CGPoint(x: frame.width/2, y: frame.height/2), radius: (frame.width - 1.5)/2, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(1.5 * .pi), clockwise: true)
        trackLayer.path = path.cgPath
        progressLayer.path = path.cgPath
    }
    
    fileprivate func configureSpeedLabel() {
        // this all only needs to be done once -- on init
        //  the only thing that will change is the text
        speedLabel.translatesAutoresizingMaskIntoConstraints = false
        speedLabel.text = String(speed)
        speedLabel.font = UIFont(name: "TimesNewRomanPSMT", size: 24)
        speedLabel.textColor = UIColor.black
        speedLabel.isOpaque = true
        self.addSubview(speedLabel)
        NSLayoutConstraint.activate([
            speedLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor),
            speedLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor)
        ])
    }
    fileprivate func createCircularPath() {
        // this all only needs to be done once -- on init
        self.backgroundColor = UIColor.clear

        // set the initial properties
        trackLayer.fillColor = UIColor.clear.cgColor
        trackLayer.strokeColor = trackColor.cgColor
        trackLayer.opacity = 0.3
        trackLayer.lineWidth = 10.0
        trackLayer.strokeEnd = 1.0
        
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.strokeColor = progressColor.cgColor
        progressLayer.lineWidth = 10.0
        progressLayer.strokeEnd = 0.0

        // add these sublayers
        self.layer.addSublayer(trackLayer)
        self.layer.addSublayer(progressLayer)
    }
    
}

控制器类示例

class CPVExampleViewController: UIViewController {
    
    let cpv = CircularProgressView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemYellow
        
        cpv.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(cpv)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            cpv.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            cpv.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            cpv.widthAnchor.constraint(equalToConstant: 280.0),
            cpv.heightAnchor.constraint(equalTo: cpv.widthAnchor),
        ])
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if cpv.speed >= 100 {
            cpv.speed = 0
        } else {
            cpv.speed += 10
        }
    }
}

结果:

enter image description here

每次点击任意位置都会将

.speed
增加
10
——直到到达
100
,然后它将重置为
0

© www.soinside.com 2019 - 2024. All rights reserved.