Использование NSLayoutConstraints для выравнивания динамических представлений по вертикали в ScrollView с помощью Swift
У меня есть приложение, которое имеет представление, которое динамически генерируется и может отличаться каждый раз при загрузке представления. Основное представление содержит 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
но нигде не было видно. Что я делаю не так? Все, что нужно, - это убедиться, что вершины каждого вида выровнены ниже предыдущего вида и остаются такими независимо от высоты вида.
кроме того, поскольку все эти представления добавляются в scrollview, используя ограничения макета выше, как установить правильный размер содержимого представления прокрутки?
1 ответов
так что вы хотите, что-то вроде этого:
настройка размера содержимого вида прокрутки с автозапуском объясняется в техническое Примечание TN2154: UIScrollView и 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
}
}