简体   繁体   中英

UIView frame center in IBOutlet initialization is incorrect

I have a progress bar that's supposed to be rendered at the center of a view, but ends up off-center because of Auto Layout.

class ProgressView: UIView {
    private let progressLayer: CAShapeLayer = CAShapeLayer()

    private var progressLabel: UILabel

    required init?(coder aDecoder: NSCoder) {
        progressLabel = UILabel()
        super.init(coder: aDecoder)
        createProgressLayer()
        createLabel()
    }

    override init(frame: CGRect) {
        progressLabel = UILabel()
        super.init(frame: frame)
        createProgressLayer()
        createLabel()
    }

    private func createProgressLayer() {
        let startAngle = CGFloat(3*M_PI_2)
        let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
        let centerPoint = CGPointMake(CGRectGetWidth(bounds)/2, CGRectGetHeight(bounds)/2)

        let gradientMaskLayer = gradientMask()
        progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: CGRectGetWidth(frame)/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
        progressLayer.backgroundColor = UIColor.clearColor().CGColor
        progressLayer.fillColor = nil
        progressLayer.strokeColor = UIColor.blackColor().CGColor
        progressLayer.lineWidth = 4.0
        progressLayer.strokeStart = 0.0
        progressLayer.strokeEnd = 0.0

        gradientMaskLayer.mask = progressLayer
        layer.addSublayer(gradientMaskLayer)
    }

    func animateProgressView() {
        progressLayer.strokeEnd = 0.0

        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = CGFloat(0.0)
        animation.toValue = CGFloat(1.0)
        animation.duration = 2.0
        animation.delegate = self
        animation.removedOnCompletion = false
        animation.additive = true
        animation.fillMode = kCAFillModeForwards
        progressLayer.addAnimation(animation, forKey: "strokeEnd")
    }
}

This code is called as follows:

class MainPageController: UIViewController {

    @IBOutlet var progressView : ProgressView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidLayoutSubviews() {
        progressView.animateProgressView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

And ends up drawing the circle off-center. If I manually edit the circle center, the right and bottom bars seem to be cut-off. If I turn auto-layout off, it works fine. What am I doing wrong?

圆偏心

Storyboard:

情节提要查看

Thanks for posting the constrains from the storyboard, I can see whats causing it now.

ProgessView is setup with two constraints, one to keep it square and another to make its height 1/3 of the views height. This means the the size of the view that you see in the storyboard is not going the same as one the device.

init?(coder aDecoder: NSCoder) is called when loading a view from a storyboard. It's called before Auto Layout runs so the values you get for bounds and frame are based on the size in the storyboard which is 200x200. Then Auto Layout runs and determines the size for your phone (which looks like an iPhone 6) should be 222x222. Based on your screenshot, it looks like you have roughly 22pt of extra space on the right and bottom of your progress view.


What you'll want to do is resize your progress layer after Auto Layout sets your view to the proper size. The best place to do that would be in layoutSubviews by moving some line from createProgressLayer

func layoutSubviews() {
    let startAngle = CGFloat(3*M_PI_2)
    let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
    let centerPoint = CGPointMake(bounds.width/2, bounds.height/2)

    progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
}

在Interface Builder中,将Progress View的内容模式更改为重绘,并覆盖drawRect并从此处调用createProgressLayer。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM