我正在从xib中添加一个视图到我的ViewController中。然后我将其约束实际适合它
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
...
...
view!.addSubview(gamePreview)
gamePreview.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 9.0, *) {
// Pin the leading edge of myView to the margin's leading edge
gamePreview.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
//Pin the trailing edge of myView to the margin's trailing edge
gamePreview.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
} else {
// Fallback on earlier versions
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .TrailingMargin, relatedBy: .Equal, toItem: view, attribute: .TrailingMargin, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .LeadingMargin, relatedBy: .Equal, toItem: view, attribute: .LeadingMargin, multiplier: 1, constant: 0))
}
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}
我正在尝试做什么:实际上适合我的视图将其限制在顶部,前导,跟踪到ViewController的视图,并使用前缀高度。我添加到主视图的视图有自己的透明背景视图,因此不需要边距(视图意味着设备的宽度大小,所以)。
我已经放置了2对线,这些线应该是相同的(在我的尝试中)和if,因为if中的前2行在iOS9中实际可用>只是,虽然我试图在else语句中为每个设备做同样的事情(从iOS 8开始)。
这就是我得到的:
iOS9 +左侧,iOS8 +右侧。透明背景被涂成红色以显示发生了什么(不要介意在图像中的不同高度,它们在app中的高度相等,而是在左右两侧查看增加的边距)
我也试过AutoLayoutDSL-Swift
,但没有帮助,我不是专家,但每次尝试都只会让事情变得更糟。
如何使用经典的NSLayoutConstraints方法编写这些约束,以及如何使用AutoLayoutDSL或其分支框架以更好的方式编写所有约束? (或另一种选择,但现在大多数时候我都关注官方文库)
答案 0 :(得分:21)
您需要使用leading
和trailing
属性,而不是leadingMargin
和trailingMargin
属性:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
...
...
view!.addSubview(gamePreview)
gamePreview.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}
答案 1 :(得分:2)
感谢@ Paulw11 ...这是解决方案
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
此外,我设法重写它,因为它使用AutoLayoutDSL-Swift
对任何感兴趣的人
view => gamePreview.trailing == view.trailing
=> gamePreview.leading == view.leading
=> gamePreview.height == 131
=> gamePreview.top == view.top + self.navigationController!.navigationBar.bounds.height + UIApplication.sharedApplication().statusBarFrame.size.height
最后一行有点长,因为view.top指的是真正的视图顶部,并没有考虑statusBar和navigationBar高度添加的填充。它们可以被替换为常数,等待有人提出更优雅的解决方案。
答案 2 :(得分:1)
SWIFT 4更新
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: stackView, attribute: .trailing, multiplier: 1, constant: 0))
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: stackView, attribute: .leading, multiplier: 1, constant: 0))
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: self.addLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0))
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,multiplier: 1,
constant: 131))
答案 3 :(得分:0)
为什么不使用约束激活?您可以这样做:
var anchors = [NSLayoutConstraint]()
anchors.append(view.topAnchor.constraint(equalTo: gamePreview.topAnchor, constant: 0))
anchors.append(view.leadingAnchor.constraint(equalTo: gamePreview.leadingAnchor, constant: 0))
anchors.append(view.trailingAnchor.constraint(equalTo: gamePreview.trailingAnchor, constant: 0))
anchors.append(view.heightAnchor.constraint(equalTo: gamePreview.heightAnchor, multiplier: 1, constant: 131))
NSLayoutConstraint.activate(anchors)
这是另一个。希望能帮助到你。您可以根据父/子交换view
和gamePreview
,也可以为约束创建通用的辅助扩展。我在YouTuber Here提供的教程中找到了一个,并对其进行了少许修改以接受开头/结尾,左右约束。您也可以在下面添加safeLayoutGuide
,这使其面向未来。像这样:
func anchor(_ top: UIView? = nil, left: UIView? = nil, bottom: UIView? = nil, right: UIView? = nil, width: UIView? = nil, height: UIView? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0, isForLeading: Bool = false) -> [NSLayoutConstraint] {
translatesAutoresizingMaskIntoConstraints = false
var anchors = [NSLayoutConstraint]()
if #available(iOS 11.0, *) {
if let top = top {
anchors.append(topAnchor.constraint(equalTo: top.safeAreaLayoutGuide.topAnchor, constant: topConstant))
}
if let left = left {
if isForLeading {
anchors.append(leadingAnchor.constraint(equalTo: left.safeAreaLayoutGuide.leadingAnchor, constant: leftConstant))
} else {
anchors.append(leftAnchor.constraint(equalTo: left.safeAreaLayoutGuide.leftAnchor, constant: leftConstant))
}
}
if let bottom = bottom {
anchors.append(bottomAnchor.constraint(equalTo: bottom.safeAreaLayoutGuide.bottomAnchor, constant: -bottomConstant))
}
if let right = right {
if isForLeading {
anchors.append(trailingAnchor.constraint(equalTo: right.safeAreaLayoutGuide.leadingAnchor, constant: rightConstant))
} else {
anchors.append(rightAnchor.constraint(equalTo: right.safeAreaLayoutGuide.rightAnchor, constant: -rightConstant))
}
}
if let width = width {
anchors.append(widthAnchor.constraint(equalTo: width.safeAreaLayoutGuide.widthAnchor, multiplier: 1, constant: widthConstant))
} else if widthConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
}
if let height = height {
anchors.append(heightAnchor.constraint(equalTo: height.safeAreaLayoutGuide.heightAnchor, multiplier: 1, constant: widthConstant))
} else if heightConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: heightConstant))
}
anchors.forEach({$0.isActive = true})
} else {
if let top = top {
anchors.append(topAnchor.constraint(equalTo: top.topAnchor, constant: topConstant))
}
if let left = left {
if isForLeading {
anchors.append(leadingAnchor.constraint(equalTo: left.leadingAnchor, constant: leftConstant))
} else {
anchors.append(leftAnchor.constraint(equalTo: left.leftAnchor, constant: leftConstant))
}
}
if let bottom = bottom {
anchors.append(bottomAnchor.constraint(equalTo: bottom.bottomAnchor, constant: -bottomConstant))
}
if let right = right {
if isForLeading {
anchors.append(trailingAnchor.constraint(equalTo: right.leadingAnchor, constant: rightConstant))
} else {
anchors.append(rightAnchor.constraint(equalTo: right.rightAnchor, constant: -rightConstant))
}
}
if let width = width {
anchors.append(widthAnchor.constraint(equalTo: width.widthAnchor, multiplier: 1, constant: widthConstant))
} else if widthConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
}
if let height = height {
anchors.append(heightAnchor.constraint(equalTo: height.heightAnchor, multiplier: 1, constant: widthConstant))
} else if heightConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: heightConstant))
}
anchors.forEach({$0.isActive = true})
}
return anchors
}
然后这样称呼它:
_ = view.anchor(gamePreview, left: gamePreview, right: gamePreview, height: gamePreview, heightConstant: 131, isForLeading: true)