Swift 3 - 以编程方式创建标题栏约束

问题描述:

我正在使用Swift 3,iOS 10,XCode 8.2。Swift 3 - 以编程方式创建标题栏约束

在我的代码中,我需要以编程方式创建一个UIViewController,因此也需要以编程方式指定其布局和内容。

@IBAction func testViewController() { 

    let detailViewController = UIViewController() 
    detailViewController.view.backgroundColor = UIColor.white 

    let titleLabel: UILabel = { 
     let label = UILabel() 
     label.translatesAutoresizingMaskIntoConstraints = false 
     label.backgroundColor = UIColor.blue 
     label.text = "Scan Results" 
     label.textAlignment = .center 
     label.font = UIFont.boldSystemFont(ofSize: 18) 
     label.textColor = UIColor.white 
     return label 
    }() 

    let titleConstraints: [NSLayoutConstraint] = [ 
     NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 40) 
    ] 

    detailViewController.view.addSubview(titleLabel) 

    detailViewController.view.addConstraints(titleConstraints) 

    self.navigationController?.pushViewController(detailViewController, animated: true) 
} 

在垂直视图(忽略所有的其他垃圾;仅仅着眼蓝色标题栏上):

enter image description here

但在水平视图:

enter image description here

什么是正确的约束设置,以便占用整个酒吧的宽度,并没有多余的空间自顶部状态栏消失时水平?

编辑

使@thexande建议后,我得到了一个错误:

[LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x608000098100 UILabel:0x7fe35b60edc0'Scan Results'.left == UIView:0x7fe35b405c20.left (inactive)> When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug. 2017-02-24 21:01:59.807 EOB-Reader[78109:10751346] * Assertion failure in -[UIView _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.6.21/NSLayoutConstraint_UIKitAdditions.m:649 2017-02-24 21:01:59.951 EOB-Reader[78109:10751346] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Impossible to set up layout with view hierarchy unprepared for constraint.'

我也更新了我的代码在原岗位。

发生这种情况的原因是因为您正在使用框架。您根据屏幕的宽度计算了框架。你不需要框架,你可以使用自动布局来完成这一切。相反,您应该使用约束将您的标签固定在超级视图边界上,并给它一个静态高度。例如:

lazy var titleConstraints: [NSLayoutConstraint] = [ 
    NSLayoutConstraint(item: self.titleLabel, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0), 
    NSLayoutConstraint(item: self.titleLabel, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0), 
    NSLayoutConstraint(item: self.titleLabel, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0), 
    NSLayoutConstraint(item: self.titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 40) 
] 

然后,在viewDidLoad中()

self.view.addConstraints(titleConstraints) 

你完全可以简化您的标签声明,像这样。不要忘了自动调整大小掩蔽标志得到限制正常工作:

let titleLabel: UILabel = { 
    let label = UILabel() 
    label.translatesAutoresizingMaskIntoConstraints = false 
    label.backgroundColor = UIColor.blue 
    label.text = "Scan Results" 
    label.textAlignment = .center 
    label.textColor = UIColor.white 
    return label 
}() 

最后,你在做怪数学,让您的视图控制器的顶部紧靠您的导航栏控制器的底部。删除所有垃圾,并把在viewDidLoad中()以下的,让您的视图控制器的右上方对你UINavigationBar的底部:

self.edgesForExtendedLayout = [] 

更新:

这里的问题是要附加的意见和限制到尚未分配的视图控制器中。

我们在viewDidLoad()中追加子视图和约束的原因是因为我们无法在视图....加载到内存之前添加子视图和约束。否则,它不在那里,你会得到上面的错误。考虑打破了你的detailViewController成一个类的声明,就像这样:

class detailViewController: UIViewController { 
let eobTitleLabel: UILabel = { 
    let label = UILabel() 
    label.translatesAutoresizingMaskIntoConstraints = false 
    label.backgroundColor = UIColor.blue 
    label.text = "Scan Results" 
    label.textAlignment = .center 
    label.font = UIFont.boldSystemFont(ofSize: 18) 
    label.textColor = UIColor.white 
    return label 
}() 

    lazy var eobTitleConstraints: [NSLayoutConstraint] = [ 
     NSLayoutConstraint(item: self.eobTitleLabel, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: self.eobTitleLabel, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: self.eobTitleLabel, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0), 
     NSLayoutConstraint(item: self.eobTitleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 40) 
    ] 

    override func viewDidLoad() { 
     self.view.addSubview(eobTitleLabel) 
     self.view.addConstraints(self.eobTitleConstraints) 
    } 
} 

而且,不脱落的进攻,但你的代码是怎样的一个烂摊子。在未来应该避免的事情:

  1. 将限制添加到不存在的标签。 (重命名修复约束的标签)
  2. 您正在使用outlet方法声明变量。不要这样做,在类级别声明方法和属性。
  3. 阅读关于OOP以及它如何在swift中实现。这将帮助你理解的方法和模式来完成你的任务:)
+0

这是一个很大的帮助。谢谢。我提出了您的建议更改,但是我收到了一个包含在我编辑的原始文章中的错误。 – noblerare

+0

对不起。我把你的建议提取到一个单独的'ViewController'类中,然后我将它实例化。感谢你的帮助! – noblerare

+0

当然!祝你好运! – thexande