kentya6 / KYCircularProgress

Flexible progress bar written in Swift.
MIT License
1.15k stars 115 forks source link

Autolayout issues when KYCircularProgress created programmatically #29

Open ghost opened 4 years ago

ghost commented 4 years ago

I have issue setting correct width and height for progress view.

 let circularProgressView : KYCircularProgress = {
        // this way (without some default frame) it doesnt work at all, even though autolayout sets frame later.
        //let circularProgress = KYCircularProgress()

        // Random height/width
        let circularProgress = KYCircularProgress(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        circularProgress.lineWidth = 3.2
        circularProgress.guideLineWidth = 2.8
        circularProgress.lineCap = CAShapeLayerLineCap.round.rawValue
        circularProgress.translatesAutoresizingMaskIntoConstraints = false
        circularProgress.backgroundColor = .white
        return circularProgress
    }()

For this code, and constrainting circularProgressView to 5 for top, bottom, trailing and aspectRatio 1 (perfect square):

circularProgressView.topAnchor.constraint(equalTo: graphContainer.topAnchor, constant: 5).isActive = true
        circularProgressView.trailingAnchor.constraint(equalTo: graphContainer.trailingAnchor, constant: -5).isActive = true
        circularProgressView.bottomAnchor.constraint(equalTo: graphContainer.bottomAnchor, constant: -5).isActive = true
        circularProgressView.widthAnchor.constraint(equalTo: circularProgressView.heightAnchor, multiplier: 1).isActive = true

I am getting following result

Screen Shot 2020-02-06 at 5 40 30 PM

As you can see, autolayout setting correct frame according to white background color, inner circleViews are resized (from 100, 100 to 41, 41 frame). But inner circles are not perfectly centered, approximately: (left: 5 top: 5, bottom: 8, right: 8), and dont have size I need (same as white circle). Am I missing something? circularProgressView.setNeedsLayout on parent LayoutSubviews doesnt work.

Swift 5, XCode 11.3.1 (11C504)

ghost commented 4 years ago

I believe this behavior is due to following code:

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

        setNeedsLayout()
        layoutIfNeeded()
    }

layout right after initialization cause all frames set, lazy variables initialize and calculate, even if there is no frame, and more importantly, positions calculated using initial value of lineWidth = 8 and hardcoded width and height frame.

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

I believe this one will solve exact issue, and allows autolayout without frame using let circularProgress = KYCircularProgress(). But I dont know the initial purpose of these lines so cant say its solution