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

Posted

技术标签:

【中文标题】IBOutlet 初始化中的 UIView 框架中心不正确【英文标题】:UIView frame center in IBOutlet initialization is incorrect 【发布时间】:2015-11-16 02:05:16 【问题描述】:

我有一个进度条应该在视图的中心呈现,但由于自动布局而最终偏离中心。

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

这段代码调用如下:

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.
    

最后画出偏离中心的圆。如果我手动编辑圆心,右侧和底部的栏似乎被切断了。如果我关闭自动布局,它工作正常。我做错了什么?

故事板:

【问题讨论】:

你能附上你的 xib/storyboard 的截图吗?那里的约束肯定会影响到这一点。 【参考方案1】:

感谢您发布情节提要中的约束,我现在可以看到是什么原因造成的。

ProgessView 设置了两个约束,一个是让它保持正方形,另一个是让它的高度为视图高度的 1/3。这意味着您在故事板中看到的视图大小与设备不同。

init?(coder aDecoder: NSCoder) 在从情节提要加载视图时调用。它在自动布局运行之前被调用,因此您为 boundsframe 获得的值基于故事板中的大小,即 200x200。然后自动布局运行并确定您的手机(看起来像 iPhone 6)的尺寸应该是 222x222。根据您的屏幕截图,您的进度视图的右侧和底部似乎有大约 22pt 的额外空间。


您要做的是在自动布局将您的视图设置为适当大小后调整进度层的大小。这样做的最佳地点是在layoutSubviews,通过从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

【讨论】:

这正是我想要的。非常感谢@CleverError【参考方案2】:

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

【讨论】:

感谢您的建议。不幸的是,这并没有解决问题

以上是关于IBOutlet 初始化中的 UIView 框架中心不正确的主要内容,如果未能解决你的问题,请参考以下文章

当从不同的类调用更改时,UIView IBOutlet 不会更改

Swift 中的 UIView 子类:IBOutlet 在展开时发现为零

UIView 类中的 CollectionView IBOutlet 返回 nil - 只是有时?

如何从 XIB 文件访问 ViewController 中的 IBoutlet

未设置自定义 UIView iboutlet

更改 UIView 框架大小不会更改 UITableview 框架原点 y