简体   繁体   English

IBOutlet初始化中的UIView框架中心不正确

[英]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. ProgessView设置有两个约束,一个约束使其保持正方形,另一个约束使其高度为视图高度的1/3。 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. 从情节init?(coder aDecoder: NSCoder)板加载视图时会调用init?(coder aDecoder: NSCoder) 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. 它在自动版式运行之前被调用,因此您获得的boundsframe的值基于情节提要中200x200的大小。 Then Auto Layout runs and determines the size for your phone (which looks like an iPhone 6) should be 222x222. 然后运行“自动布局”,并确定手机(看起来像iPhone 6)的尺寸应为222x222。 Based on your screenshot, it looks like you have roughly 22pt of extra space on the right and bottom of your progress view. 根据屏幕快照,您似乎在进度视图的右侧和底部大约有22pt的额外空间。


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 最好的方法是通过从createProgressLayer移动一些行在layoutSubviews

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。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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