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.