Home > Software design >  Initializing an instance from Custom ProgressBar Class into UItableviewCell
Initializing an instance from Custom ProgressBar Class into UItableviewCell

Time:12-03

I'm trying to create a circular progressBar with timer function in my UItableviewCell class. I have created a custom class timer, and I am using Jonni's progressBar template (Credit to Jonni Åkesson) from - enter image description here

Below is my code and I am unable to see both front CAShapeLayer and background CAShapeLayer. I am suspecting a logical error when I initialize constant "progressBar".

Please advise if it is possible to utilize the Custom ProgressBar Class, instead of re-writing the entire code.

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)
    
    }

Below is the Custom ProgressBar Class from source file.

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
}

CodePudding user response:

Resolve the issue by loading the background and foreground progress bars in layoutSubViews function.

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
        }
        
    }
  • Related