我的目标是创建一个堆栈视图,它可以容纳任意(~5-10(排列的子视图,如果其高度高于其包含的视图,则可以滚动。 为此,我使用滚动视图。
我的理解是,如果每个排列的子视图都有明确的高度约束,则distribution
设置为fill
的堆栈视图应该具有固有的内容大小。 因此,我可以将堆栈视图添加到滚动视图中,滚动可以从堆栈视图的内部内容大小中获取其内容大小。
我还在尝试使这个滚动堆栈视图对框架(从键盘(的变化具有鲁棒性。
我花了很多时间阅读了许多关于Scroll View和StackView的长篇文章以及所有编程指南,但无法使其完美运行。
下面的代码和它的轻微变化总是给出一个content size is ambiguous
或Height is ambiguous for Scroll View
。 当键盘弹出时(通过点击堆栈视图中的文本视图(,我只是从滚动视图的底部约束常量中减去 400。 我的想法是,滚动视图的框架/边界将小于堆栈视图的固有内容高度,并且会发生滚动。 但是,屏幕只是空白。 控制台中也没有约束日志。
我花了大量时间思考这种情况中的所有考虑因素,但这似乎超出了我的范围。 我将非常感谢有关滚动视图中堆栈视图主题的任何帮助或指示。
这是我目前的实验:
class ViewController: UIViewController {
let scrollView = UIScrollView()
var scrollViewBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// stack view setup (one blue and hellow view at 100 height)
let stackView = UIStackView()
stackView.distribution = .fill
stackView.axis = .vertical
let v1 = UIView()
v1.backgroundColor = .blue
let v2 = UITextView()
v2.backgroundColor = .yellow
stackView.addArrangedSubview(v1)
stackView.addArrangedSubview(v2)
// scroll
scrollView.addSubview(stackView)
view.addSubview(scrollView)
// constraints for stack view arranged views
v1.heightAnchor.constraint(equalToConstant: 100).isActive = true
v2.heightAnchor.constraint(equalToConstant: 100).isActive = true
// pin scroll view in main view
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
// pin scroll view to stack view's bottom anchor
scrollViewBottomConstraint = scrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 0)
scrollViewBottomConstraint.isActive = true
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
stackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
// constrain "content view to main view and not scroll view."
stackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1).isActive = true
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.handleKeyboard),
name: Notification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.handleKeyboard),
name: Notification.Name.UIKeyboardWillHide,
object: nil)
}
func handleKeyboard(notification: Notification) {
scrollViewBottomConstraint.constant = -400
}
}
我在这里添加我的工作示例:
class ViewController: UIViewController {
let scrollView = UIScrollView()
var scrollViewBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// stack view setup (one blue and hellow view at 100 height)
let stackView = UIStackView()
stackView.distribution = .fill
stackView.axis = .vertical
let v1 = UIView()
v1.backgroundColor = .blue
let v2 = UITextView()
v2.backgroundColor = .yellow
let v3 = UITextView()
v3.backgroundColor = .green
let v4 = UITextView()
v4.backgroundColor = .brown
stackView.addArrangedSubview(v1)
stackView.addArrangedSubview(v2)
stackView.addArrangedSubview(v3)
stackView.addArrangedSubview(v4)
// scroll
scrollView.addSubview(stackView)
view.addSubview(scrollView)
// constraints for stack view arranged views
v1.heightAnchor.constraint(equalToConstant: 200).isActive = true
v2.heightAnchor.constraint(equalToConstant: 200).isActive = true
v3.heightAnchor.constraint(equalToConstant: 180).isActive = true
v4.heightAnchor.constraint(equalToConstant: 250).isActive = true
// pin scroll view in main view
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 100).isActive = true
// pin scroll view to stack view's bottom anchor
scrollViewBottomConstraint = scrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 0)
scrollViewBottomConstraint.isActive = true
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
stackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
// constrain "content view to main view and not scroll view."
stackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1).isActive = true
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.handleKeyboard),
name: Notification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.handleKeyboard),
name: Notification.Name.UIKeyboardWillHide,
object: nil)
}
func handleKeyboard(notification: Notification) {
scrollViewBottomConstraint.constant = -400
}
}