我花了好几个小时试图找出妨碍我的约束布局工作的因素。我有一个名为ABSegment
的视图,它只包含一个UILabel,它应该居中并且高度和宽度与其超视图相同。
我将包含此UIView子视图的整个类定义,以显示我已完成的操作。
import UIKit
class ABSegment: UIView {
let titleLabel = UILabel()
init(withTitle title: String) {
titleLabel.text = title
titleLabel.textAlignment = .center
super.init(frame: CGRect.zero)
translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabel)
backgroundColor = UIColor.blue
}
override func layoutSubviews() {
super.layoutSubviews()
logFrames()
}
func logFrames() {
print("self.frame is \(frame)")
print("titleLabel.frame is \(titleLabel.frame)")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateConstraints() {
logFrames()
titleLabel.removeConstraints(titleLabel.constraints)
let centerX = NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let centerY = NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)
let width = NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
let height = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([centerX, centerY, width, height])
super.updateConstraints()
}
}
我怀疑的一件事是我没有用initWithFrame初始化这个视图。相反,我将帧设置推迟到构造这些视图的代码中。因此,构造这些的代码不会设置框架。可以在Storyboard中设置框架,或者像这样:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let frame = CGRect(x: view.bounds.origin.x + 150, y: view.bounds.origin.y + 200, width: 100, height: 100)
segment.frame = frame
segment.layoutSubviews()
}
我的理解是,因为我正在调用segment.layoutSubviews()
,所以ABSegment View应该有一个更改,以便在最后一帧中应用先前激活的约束。
有许多不同的设置和事情以正确的顺序排列,没有反馈,除了没有看到标签出现。
答案 0 :(得分:1)
我在您的代码中看到的主要问题:
每次调用updateConstraints
时都要添加和删除约束。您只需在创建视图时设置一次约束。
您在translatesAutoresizingMaskIntoConstraints = false
上设置ABSegment
。不要这样做。这告诉自动布局您将使用约束指定ABSegment
的大小和位置,并且显然您正在使用frame
来实现此目的。
以下是重构代码:
class ABSegment: UIView {
let titleLabel = UILabel()
// Computed property to allow title to be changed
var title: String {
set {
titleLabel.text = newValue
}
get {
return titleLabel.text ?? ""
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupLabel(title: "")
}
convenience init(title: String) {
self.init(frame: CGRect.zero)
self.title = title
}
// This init is called if your view is
// set up in the Storyboard
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLabel(title: "")
}
func setupLabel(title: String) {
titleLabel.text = title
titleLabel.textAlignment = .center
addSubview(titleLabel)
backgroundColor = UIColor.blue
titleLabel.translatesAutoresizingMaskIntoConstraints = false
let centerX = NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let centerY = NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)
let width = NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
let height = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([centerX, centerY, width, height])
}
override func layoutSubviews() {
super.layoutSubviews()
logFrames()
}
func logFrames() {
print("self.frame is \(frame)")
print("titleLabel.frame is \(titleLabel.frame)")
}
override func updateConstraints() {
super.updateConstraints()
logFrames()
}
}
注意:
setupLabel
的函数中。这允许两个初始化程序调用它。title
添加了名为ABSegment
的计算属性,您可以随时使用title
更改mysegment.title = "new title"
。init(withSegment:)
变成了便利初始。它调用标准init(frame:)
,然后设置title
。使用withProperty
并不常见,因此我对其进行了更改。您可以使用ABSegment
创建var segment = ABSegment(title: "some title")
。required init?(coder aDecoder: NSCoder)
致电setupLabel
,以便ABSegment
可以与 Storyboard 中添加的视图一起使用。layoutSubviews
和updateConstraints
的覆盖以记录帧。这就是他们现在所做的一切。