将 Custom ProgressBar Class 中的实例初始化为 UItableviewCell

Initializing an instance from Custom ProgressBar Class into UItableviewCell

我正在尝试在我的 UItableviewCell class 中创建一个带有计时器功能的循环进度条。我创建了一个自定义 class 计时器,并且我正在使用 Jonni 的进度条模板(致谢 Jonni Åkesson)来自 - https://github.com/innoj/CountdownTimer.

我的代码和源模板之间唯一明显的区别是我以编程方式添加自定义 ProgressBar class UIView,而源模板使用 IBOutlet 连接到自定义 ProgressBar Class。

我的目标是确保 CAShapeLayers(实际层和背景层都如下图所示 - 来源:https://www.youtube.com/watch?v=-KwFvGVstyc

下面是我的代码,我看不到前面的 CAShapeLayer 和背景的 CAShapeLayer。我怀疑初始化常量“progressBar”时出现逻辑错误。

请告知是否可以使用自定义进度条 Class,而不是重写整个代码。

import Foundation
import UIKit
import IQKeyboardManagerSwift


class ActiveExerciseTableViewCell: UITableViewCell, UITextFieldDelegate {

    let progressBar: ProgressBar = {
        let progressBar = ProgressBar()
        return progressBar
    }()

    lazy var  activeExerciseTimerUIView: UIView = { [weak self] in
        let activeExerciseTimerUIView = UIView()
        activeExerciseTimerUIView.backgroundColor = .black
        activeExerciseTimerUIView.isUserInteractionEnabled = true
        activeExerciseTimerUIView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapTimerView)))
        return activeExerciseTimerUIView
    }()

    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        contentView.addSubview(activeExerciseTimerUIView)

    }

    override func layoutSubviews() {
        super.layoutSubviews()

        setUpActiveExerciseUIViewLayout()

}

func setUpActiveExerciseUIViewLayout(){

activeExerciseTimerUIView.translatesAutoresizingMaskIntoConstraints = false
        activeExerciseTimerUIView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        
        activeExerciseTimerUIView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentView.frame.height-tableviewContentViewTabBarHeight)*0.25).isActive = true
        activeExerciseTimerUIView.widthAnchor.constraint(equalToConstant: 225).isActive = true
        activeExerciseTimerUIView.heightAnchor.constraint(equalToConstant: 225).isActive = true
        activeExerciseTimerUIView.layer.cornerRadius = activeExerciseTimerUIView.frame.width/2

        
        progressBar.frame = CGRect(
            x: 0,
            y: 0,
            width: activeExerciseTimerUIView.frame.width,
            height: activeExerciseTimerUIView.frame.height)
        
        self.activeExerciseTimerUIView.addSubview(progressBar)
    
    }

下面是源文件中的自定义进度条 Class。

import UIKit


class ProgressBar: UIView, CAAnimationDelegate {

fileprivate var animation = CABasicAnimation()
fileprivate var animationDidStart = false
fileprivate var timerDuration = 0

lazy var fgProgressLayer: CAShapeLayer = {
    let fgProgressLayer = CAShapeLayer()
    return fgProgressLayer
}()

lazy var bgProgressLayer: CAShapeLayer = {
    let bgProgressLayer = CAShapeLayer()
    return bgProgressLayer
}()


required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)!
    loadBgProgressBar()
    loadFgProgressBar()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    loadBgProgressBar()
    loadFgProgressBar()
}


fileprivate func loadFgProgressBar() {
    
    let startAngle = CGFloat(-Double.pi / 2)
    let endAngle = CGFloat(3 * Double.pi / 2)
    let centerPoint = CGPoint(x: frame.width/2 , y: frame.height/2)
    let gradientMaskLayer = gradientMask()
    fgProgressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2 - 30.0, startAngle:startAngle, endAngle:endAngle, clockwise: true).cgPath
    fgProgressLayer.backgroundColor = UIColor.clear.cgColor
    fgProgressLayer.fillColor = nil
    fgProgressLayer.strokeColor = UIColor.black.cgColor
    fgProgressLayer.lineWidth = 4.0
    fgProgressLayer.strokeStart = 0.0
    fgProgressLayer.strokeEnd = 0.0
    
    gradientMaskLayer.mask = fgProgressLayer
    layer.addSublayer(gradientMaskLayer)
}


fileprivate func gradientMask() -> CAGradientLayer {
    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = bounds
    gradientLayer.locations = [0.0, 1.0]
    let colorTop: AnyObject = CustomColor.lime.cgColor
    let colorBottom: AnyObject = CustomColor.lime.cgColor
    let arrayOfColors: [AnyObject] = [colorTop, colorBottom]
    gradientLayer.colors = arrayOfColors
    return gradientLayer
}


fileprivate func loadBgProgressBar() {
    
    let startAngle = CGFloat(-Double.pi / 2)
    let endAngle = CGFloat(3 * Double.pi / 2)
    let centerPoint = CGPoint(x: frame.width/2 , y: frame.height/2)
    let gradientMaskLayer = gradientMaskBg()
    bgProgressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2 - 30.0, startAngle:startAngle, endAngle:endAngle, clockwise: true).cgPath
    bgProgressLayer.backgroundColor = UIColor.clear.cgColor
    bgProgressLayer.fillColor = nil
    bgProgressLayer.strokeColor = UIColor.black.cgColor
    bgProgressLayer.lineWidth = 4.0
    bgProgressLayer.strokeStart = 0.0
    bgProgressLayer.strokeEnd = 1.0
    
    gradientMaskLayer.mask = bgProgressLayer
    layer.addSublayer(gradientMaskLayer)
}


fileprivate func gradientMaskBg() -> CAGradientLayer {
    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = bounds
    gradientLayer.locations = [0.0, 1.0]
    let colorTop: AnyObject = CustomColor.strawberry.cgColor
    let colorBottom: AnyObject = CustomColor.strawberry.cgColor
    let arrayOfColors: [AnyObject] = [colorTop, colorBottom]
    gradientLayer.colors = arrayOfColors
    
    return gradientLayer
}

通过在 layoutSubViews 函数中加载背景和前景进度条来解决问题。

ProgressBar.swift

import UIKit
import Pulsator


class ProgressBar: UIView, CAAnimationDelegate {
    
    fileprivate var animation = CABasicAnimation()
    fileprivate var animationDidStart = false
    fileprivate var updatedAnimationAdded = false
    fileprivate var updateExecuted = false
    fileprivate var totalTimerDuration = 0
    
    fileprivate var isProgressBarAdded:Bool = false
    fileprivate var barlineWidth: CGFloat = 8
    
//    let pulsator = Pulsator()
    
//    fileprivate var width: CGFloat
//    fileprivate var height: CGFloat
//
    lazy var fgProgressLayer: CAShapeLayer = {
        let fgProgressLayer = CAShapeLayer()
        return fgProgressLayer
    }()
    
    lazy var bgProgressLayer: CAShapeLayer = {
        let bgProgressLayer = CAShapeLayer()
        return bgProgressLayer
    }()
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        loadBgProgressBar()
        loadFgProgressBar()
    }

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

    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        if self.frame.width > 0 && self.frame.height > 0 && isProgressBarAdded == false {
            loadBgProgressBar()
            loadFgProgressBar()
            
            isProgressBarAdded = true
        }
        
    }