我一直在网上寻找很多片段,但我仍然找不到我的问题的答案。我的问题是我有一个scrollView(SV),我想以编程方式在scrollView(SV)内添加一个按钮,其父视图的宽度和高度相同,即scrollView(SV),这样当用户旋转设备按钮时,它将具有相同的框架滚动视图(SV)。如何做 NSLayout/NSLayoutConstraint?谢谢
11 回答
如果有人正在寻找一个Swift 解决方案——我会创建一个 Swift扩展,UIView
每次你想将一个子视图框架绑定到它的超级视图边界时,它都会为你提供帮助:
斯威夫特 2:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
斯威夫特 3:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
斯威夫特 4.2:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.topAnchor, constant: 0).isActive = true
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: 0).isActive = true
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 0).isActive = true
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: 0).isActive = true
}
}
然后简单地这样称呼它:
// after adding as a subview, e.g. `view.addSubview(subview)`
subview.bindFrameToSuperviewBounds()
我不确定这是否是最有效的方法,但它有效..
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.translatesAutoresizingMaskIntoConstraints = NO;
// initialize
[coverForScrolView addSubview:button];
NSLayoutConstraint *width =[NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeWidth
relatedBy:0
toItem:coverForScrolView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
NSLayoutConstraint *height =[NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeHeight
relatedBy:0
toItem:coverForScrolView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
NSLayoutConstraint *top = [NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:coverForScrolView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.f];
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:coverForScrolView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
[coverForScrolView addConstraint:width];
[coverForScrolView addConstraint:height];
[coverForScrolView addConstraint:top];
[coverForScrolView addConstraint:leading];
此链接可以帮助您,按照说明操作: http ://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2
编辑 :
使用以下代码片段,其中 subview 是您的 subivew。
[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];
addConstraint
UIView和removeConstraint
方法将被弃用,因此值得使用“约束创建便利”:
view.topAnchor.constraint(equalTo: superView.topAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: 0).isActive = true
view.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: 0).isActive = true
方法 #1:通过 UIView 扩展
这是Swift 3+中一种更实用的方法,它带有一个先决条件而不是 a (它很容易在控制台中消失)。这会将程序员错误报告为失败的构建。print
将此扩展添加到您的项目中:
extension UIView {
/// Adds constraints to the superview so that this view has same size and position.
/// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
func bindEdgesToSuperview() {
guard let superview = superview else {
preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
}
translatesAutoresizingMaskIntoConstraints = false
["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach { visualFormat in
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
}
现在简单地这样称呼它:
// after adding as a subview, e.g. `view.addSubview(subview)`
subview.bindEdgesToSuperview()
请注意,上面的方法已经集成到我的HandyUIKit框架中,它还在您的项目中添加了一些更方便的 UI 助手。
方法 #2:使用框架
如果您在项目中经常使用编程约束,那么我建议您查看SnapKit。它使处理约束变得更加容易且不易出错。
按照文档中的安装说明将 SnapKit 包含到您的项目中。然后将其导入Swift 文件的顶部:
import SnapKit
现在您可以通过以下方式实现相同的目标:
subview.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
斯威夫特 3:
import UIKit
extension UIView {
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
斯威夫特 4使用NSLayoutConstraint
:
footerBoardImageView.translatesAutoresizingMaskIntoConstraints = false
let widthConstraint = NSLayoutConstraint(item: yourview, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: superview, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: yourview, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: superview, attribute: NSLayoutAttribute.height, multiplier: 1, constant: 0)
superview.addConstraints([widthConstraint, heightConstraint])
我从其他答案中挑选了最好的元素:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: superview.topAnchor),
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor)
])
}
}
您可以像这样使用它,例如在您的自定义 UIView 中:
let myView = UIView()
myView.backgroundColor = UIColor.red
self.addSubview(myView)
myView.bindFrameToSuperviewBounds()
作为补充答案,对于那些不反对包含第三方库的人来说,PureLayout库提供了一种方法来做到这一点。安装库后,它就像
myView.autoPinEdgesToSuperviewEdges()
作为@Dschee 解决方案的后续,这里是 swift 3.0 语法:(请注意:这不是我的解决方案,我刚刚为 Swift 3.0 修复了它)
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
我需要完全覆盖superview。其他的在方向变化时不会这样做。所以我写了一个新的——使用任意大小的乘数 20。随意改变你的需要。另请注意,这实际上使子视图比父视图大得多,这可能与要求不同。
extension UIView {
func coverSuperview() {
guard let superview = self.superview else {
assert(false, "Error! `superview` was nil – call `addSubview(_ view: UIView)` before calling `\(#function)` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
let multiplier = CGFloat(20.0)
NSLayoutConstraint.activate([
self.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: multiplier),
self.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: multiplier),
self.centerXAnchor.constraint(equalTo: superview.centerXAnchor),
self.centerYAnchor.constraint(equalTo: superview.centerYAnchor),
])
}
}