我有一个应用程序,它具有动态生成的视图,并且每次加载视图时都可以不同。主视图包含一个设置为主视图边界的ScrollView。然后将子视图动态添加到ScrollView,但这些视图的高度将不同,并且它们可以随时更改高度(例如,用户单击视图的内容并更改)。我想使用布局约束来确保每个视图保持与其上方的视图对齐,并使用一些任意填充。见下图:
现在所有填充值都设置为10(顶部,左侧和右侧)。我正在使用他们的框架手动设置这些子视图的位置,但是如果视图改变大小,这不起作用,所以我想改变它以使用NSLayoutConstraints,但我遇到了一些问题。
作为测试,我像以前一样设置子视图的框架,但后来我添加了约束:
// newView is created and its frame is initialized
self.scrlView?.addSubview(newView)
let constr = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.previousView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
NSLayoutConstraints.activateConstraints([constr])
newView.translatesAutoResizingMaskIntoConstraints = false
self.previousView = newView
但这些观点无处可见。我究竟做错了什么?所需要的只是确保每个视图的顶部在前一个视图下方对齐,并且无论视图高度如何,它们都保持这种状态。
此外,由于这些视图都已添加到滚动视图中,使用上面的布局约束如何设置滚动视图的正确内容大小?
答案 0 :(得分:5)
所以你想要这样的东西:
在Technical Note TN2154: UIScrollView And Autolayout中说明了使用自动布局设置滚动视图的内容大小。总而言之,autolayout根据滚动视图及其后代视图之间的约束设置滚动视图的contentSize
。这意味着:
您需要在滚动视图及其后代视图之间创建约束,以便正确设置滚动视图contentSize
。
您需要在切片(图片中的彩色视图)和主视图(滚动视图的超级视图)之间创建约束,以正确设置切片的宽度。从平铺到其封闭滚动视图的约束不能设置平铺的大小 - 仅滚动视图的contentSize
。
对于您在代码中创建的任何视图,如果您打算使用约束来控制其大小或位置,则还需要设置translatesAutoresizingMaskIntoConstraints = false
。否则,自动调整掩码将干扰显式约束的行为。
以下是我制作演示的方法。我使用了UIButton
子类,当点击时,将自己的高度切换到60到120点之间:
class HeightTogglingButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
heightConstraint = heightAnchor.constraint(equalToConstant: 60)
heightConstraint.isActive = true
addTarget(self, action: #selector(HeightTogglingButton.toggle(_:)), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@IBAction func toggle(_ sender: Any) {
UIView.animate(withDuration: 0.3) {
self.heightConstraint.constant = 180 - self.heightConstraint.constant
self.window?.layoutIfNeeded()
}
}
private(set) var heightConstraint: NSLayoutConstraint!
}
然后我在滚动视图中布置了十个这些按钮。我设置约束来控制每个按钮的宽度,以及每个按钮相对于其他按钮的布局。顶部和底部按钮被约束到滚动视图的顶部和底部,因此它们控制scrollView.contentSize.height
。所有按钮都被约束到滚动视图的前沿和后沿,因此它们共同控制scrollView.contentSize.width
。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
let margin: CGFloat = 10
var priorAnchor = scrollView.topAnchor
for i in 0 ..< 10 {
let button = HeightTogglingButton()
button.backgroundColor = UIColor(hue: CGFloat(i) / 10, saturation: 0.8, brightness: 0.3, alpha: 1)
button.setTitle("Button \(i)", for: .normal)
scrollView.addSubview(button)
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -2 * margin),
button.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: margin),
button.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -margin),
button.topAnchor.constraint(equalTo: priorAnchor, constant: margin)])
priorAnchor = button.bottomAnchor
}
scrollView.bottomAnchor.constraint(equalTo: priorAnchor, constant: margin).isActive = true
}
}