Допустим, я добавил больше видов в UIStackView, которые можно отобразить, как я могу сделать UIStackView
прокрутку?
Допустим, я добавил больше видов в UIStackView, которые можно отобразить, как я могу сделать UIStackView
прокрутку?
Ответы:
В случае, если кто-то ищет решение без кода , я создал пример, чтобы сделать это полностью в раскадровке, используя Auto Layout.
Вы можете получить его из GitHub .
В основном, чтобы воссоздать пример (для вертикальной прокрутки):
UIScrollView
и установите его ограничения.UIStackView
кUIScrollView
Leading
, Trailing
, Top
и Bottom
должны быть равны те изUIScrollView
Width
ограничения между UIStackView
и UIScrollView
.UIStackView
UIViews
вUIStackView
Замените Width
на Height
шаге 4 и установите Axis
= Horizontal
на шаге 5, чтобы получить горизонтальный UIStackView.
Apple Auto Layout Guide содержит целый раздел по работе с представлениями прокрутки . Некоторые соответствующие фрагменты:
- Прикрепите верхний, нижний, передний и задний края представления содержимого к соответствующим краям представления прокрутки. Представление содержимого теперь определяет область содержимого представления прокрутки.
- (Необязательно) Чтобы отключить горизонтальную прокрутку, установите ширину представления содержимого, равную ширине представления прокрутки. Представление содержимого теперь заполняет представление прокрутки по горизонтали.
- (Необязательно) Чтобы отключить вертикальную прокрутку, установите высоту представления содержимого, равную высоте представления прокрутки. Представление содержимого теперь заполняет представление прокрутки по горизонтали.
Более того:
Ваш макет должен полностью определять размер представления контента (кроме случаев, определенных в шагах 5 и 6). … Когда представление содержимого выше, чем представление прокрутки, представление прокрутки включает вертикальную прокрутку. Когда представление содержимого шире, чем представление прокрутки, представление прокрутки включает горизонтальную прокрутку.
Подводя итог, представление содержимого представления прокрутки (в данном случае, представление стека) должно быть прикреплено к его краям, и его ширина и / или высота должны быть ограничены иным образом. Это означает, что содержимое представления стека должно быть ограничено (прямо или косвенно) в направлении (ях), в котором желательна прокрутка, что может означать, например, добавление ограничения высоты для каждого представления в представлении стека с вертикальной прокруткой. Ниже приведен пример того, как разрешить вертикальную прокрутку представления прокрутки, содержащего представление стека:
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
Need constraints for: Y position or height.
эта ошибка исчезает, только если вы устанавливаете ограничение ширины и высоты для стекового представления, которое отключает вертикальную прокрутку. Этот код все еще работает для вас?
Ограничения в ответе с наибольшим количеством голосов здесь работали для меня, и я вставил изображение ограничений ниже, как создано в моей раскадровке.
Я столкнулся с двумя проблемами, о которых другие должны знать:
После добавления ограничений, аналогичных тем, которые содержатся в принятом ответе, я получу красную ошибку автоматического определения местоположения Need constraints for: X position or width
. Это было решено путем добавления UILabel в качестве подпредставления стекового представления.
Я добавляю подпредставления программно, поэтому у меня изначально не было подпредставлений на раскадровке. Чтобы избавиться от ошибок автоматического размещения, добавьте подпредставление в раскадровку, а затем удалите его при загрузке перед добавлением ваших реальных подпредставлений и ограничений.
Первоначально я пытался добавить UIButtons
в UIStackView. Кнопки и представления будут загружаться, но представление прокрутки не будет прокручиваться . Это было решено путем добавленияUILabels
в Stack View вместо кнопок. Используя те же ограничения, эта иерархия представления с UILabels прокручивается, а UIButton - нет.
Я смущен этой проблемой, поскольку UIB-кнопки , кажется, имеют IntrinsicContentSize (используется стековым представлением). Если кто-нибудь знает, почему кнопки не работают, я хотел бы знать, почему.
Вот моя иерархия представления и ограничения, для справки:
Как говорит Эйк, UIStackView
и UIScrollView
играйте вместе, смотрите здесь .
Ключевым моментом является то, что он UIStackView
обрабатывает переменную высоту / ширину для различного содержимого, а UIScrollView
затем хорошо выполняет свою работу по прокрутке / отскоку этого содержимого:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
Я хотел сделать то же самое и наткнулся на этот отличный пост. Если вы хотите сделать это программно с помощью API привязки, это путь.
Подводя итог, вставьте свой UIStackView
в ваш UIScrollView
, и установите ограничения привязки для, UIStackView
чтобы соответствовать тем из UIScrollView
:
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
Пустая полноэкранная сцена
Добавить вид прокрутки. Удерживая клавишу Control, перетащите из вида прокрутки в базовый вид , добавьте левый-правый-верхний-нижний, все ноль.
Добавьте представление стека в представлении прокрутки. Удерживая клавишу Control, перетащите из представления стека в представление прокрутки , добавьте левый-правый-верхний-нижний, все ноль.
Поместите две или три метки внутри стека.
Для наглядности сделайте цвет фона метки красным. Установите высоту этикетки до 100.
Теперь установите ширину каждой UILabel:
Удивительно, но перетаскиванием элемента управления из в UILabel
представление прокрутки, а не в представление стека, и выберите равную ширину .
Повторить:
Это так просто. Это секрет.
Секретный совет - ошибка Apple:
Он не будет работать только с одним элементом! Добавьте несколько ярлыков, чтобы демо-версия работала.
Вы сделали
Совет: вы должны добавить высоту для каждого нового элемента . Каждый элемент в любом представлении стека прокрутки должен иметь внутренний размер (например, метку) или добавлять явное ограничение высоты.
Альтернативный подход:
Выше: неожиданно, установите ширину UILabels равной ширине вида прокрутки (не вида стека).
С другой стороны ...
Итак, у вас есть два варианта:
или
Чтобы было ясно, используйте ОДИН из этих методов, НЕ делайте оба.
Для горизонтальной прокрутки. Сначала создайте a UIStackView
и a UIScrollView
и добавьте их в свой вид следующим образом:
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
Вспомнив , чтобы установить , translatesAutoresizingMaskIntoConstraints
чтобы false
на UIStackView
и UIScrollView
:
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
Чтобы все работало, задний, ведущий, верхний и нижний якоря UIStackView
должны быть равны UIScrollView
якорям:
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
Но ширина якоря UIStackView
должна быть равна или больше ширины UIScrollView
якоря:
stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true
Теперь якорь ваш UIScrollView
, например:
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo:view.trailingAnchor).isActive = true
Далее я бы предложил попробовать следующие параметры UIStackView
выравнивания и распределения:
topicStackView.axis = .horizontal
topicStackView.distribution = .equalCentering
topicStackView.alignment = .center
topicStackView.spacing = 10
Наконец, вам нужно использовать addArrangedSubview:
метод для добавления подпредставлений в ваш UIStackView.
Еще одна полезная функция, которая может оказаться полезной, заключается в том, что, поскольку UIStackView
она хранится внутри UIScrollView
, теперь у вас есть доступ к текстовым вставкам, чтобы вещи выглядели немного красивее.
let inset:CGFloat = 20
scrollView.contentInset.left = inset
scrollView.contentInset.right = inset
// remember if you're using insets then reduce the width of your stack view to match
stackView.widthAnchor.constraint(greaterThanOrEqualTo: topicScrollView.widthAnchor, constant: -inset*2).isActive = true
Просто добавьте это к viewdidload
:
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
Вы можете попробовать ScrollableStackView : https://github.com/gurhub/ScrollableStackView
Это Objective-C и Swift совместимая библиотека. Это доступно через CocoaPods .
Образец кода (Swift)
import ScrollableStackView
var scrollable = ScrollableStackView(frame: view.frame)
view.addSubview(scrollable)
// add your views with
let rectangle = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 55))
rectangle.backgroundColor = UIColor.blue
scrollable.stackView.addArrangedSubview(rectangle)
// ...
Образец кода (Objective-C)
@import ScrollableStackView
ScrollableStackView *scrollable = [[ScrollableStackView alloc] initWithFrame:self.view.frame];
scrollable.stackView.distribution = UIStackViewDistributionFillProportionally;
scrollable.stackView.alignment = UIStackViewAlignmentCenter;
scrollable.stackView.axis = UILayoutConstraintAxisVertical;
[self.view addSubview:scrollable];
UIView *rectangle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 55)];
[rectangle setBackgroundColor:[UIColor blueColor]];
// add your views with
[scrollable.stackView addArrangedSubview:rectangle];
// ...
Если у вас есть ограничение по центру стекового вида вертикально внутри прокрутки, просто удалите его.
Пример вертикального просмотра стека / прокрутки (с использованием EasyPeasy
for autolayout):
let scrollView = UIScrollView()
self.view.addSubview(scrollView)
scrollView <- [
Edges(),
Width().like(self.view)
]
let stackView = UIStackView(arrangedSubviews: yourSubviews)
stackView.axis = .vertical
stackView.distribution = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView <- [
Edges(),
Width().like(self.view)
]
Просто убедитесь, что высота каждого вашего подпредставления определена!
Прежде всего, создайте свой дизайн, желательно в Sketch, или получите представление о том, что вы хотите использовать в качестве прокручиваемого контента.
После этого создайте произвольную форму контроллера представления (выберите из инспектора атрибутов) и задайте высоту и ширину в соответствии с внутренним размером содержимого вашего представления (выбирается из инспектора размера).
После этого в контроллере представления поместите представление прокрутки, и это логика, которая, как я обнаружил, работает почти все время в iOS (может потребоваться просмотр документации этого класса представления, которую можно получить с помощью команды + клик на тот класс или через гугл)
Если вы работаете с двумя или более представлениями, то сначала начните с представления, которое было представлено ранее или является более примитивным, а затем перейдите к представлению, которое было представлено позже или является более современным. Так что здесь, так как представление прокрутки было введено сначала, начните с представления прокрутки сначала и затем перейдите к представлению стека. Здесь поместите ограничения вида прокрутки в ноль во всех направлениях относительно его суперпредставления. Поместите все свои представления в это представление прокрутки и затем поместите их в представление стека.
Во время работы с представлением стека
Сначала начните с оснований вверх (подход снизу вверх), т. Е. Если у вас есть метки, текстовые поля и изображения в вашем представлении, затем сначала разложите эти представления (в представлении прокрутки), а затем поместите их в представление стека.
После этого настройте свойство стека. Если желаемый вид все еще не достигнут, тогда используйте другой вид стека.
После создания представления поместите ограничение между представлением стека матриц и представлением прокрутки, в то время как представление стека дочерних элементов ограничения будет представлением стека матриц. Надеемся, что к этому времени он будет работать нормально, или вы можете получить предупреждение от XCode с предложениями, прочитать то, что он говорит, и реализовать их. Надеюсь, теперь у вас должен быть рабочий взгляд согласно вашим ожиданиям :).
Для вложенного или одиночного стекового вида прокрутки необходимо установить фиксированную ширину с корневым представлением. Основной вид стека, который находится внутри вида прокрутки, должен иметь такую же ширину. [Мой вид прокрутки ниже представления игнорировать его]
Установите равное ограничение ширины между UIStackView и UIScrollView.
Если кто-то ищет горизонтально прокрутки
func createHorizontalStackViewsWithScroll() {
self.view.addSubview(stackScrollView)
stackScrollView.translatesAutoresizingMaskIntoConstraints = false
stackScrollView.heightAnchor.constraint(equalToConstant: 85).isActive = true
stackScrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackScrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackScrollView.bottomAnchor.constraint(equalTo: visualEffectViews.topAnchor).isActive = true
stackScrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: stackScrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: stackScrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: stackScrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: stackScrollView.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: stackScrollView.heightAnchor).isActive = true
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.axis = .horizontal
stackView.alignment = .fill
for i in 0 ..< images.count {
let photoView = UIButton.init(frame: CGRect(x: 0, y: 0, width: 85, height: 85))
// set button image
photoView.translatesAutoresizingMaskIntoConstraints = false
photoView.heightAnchor.constraint(equalToConstant: photoView.frame.height).isActive = true
photoView.widthAnchor.constraint(equalToConstant: photoView.frame.width).isActive = true
stackView.addArrangedSubview(photoView)
}
stackView.setNeedsLayout()
}
Поместите вид прокрутки на вашу сцену и измените его размер так, чтобы он заполнил всю сцену. Затем поместите представление стека в представление прокрутки и поместите кнопку добавления элемента в представление стека. Как только все будет готово, установите следующие ограничения:
Scroll View.Leading = Superview.LeadingMargin
Scroll View.Trailing = Superview.TrailingMargin
Scroll View.Top = Superview.TopMargin
Bottom Layout Guide.Top = Scroll View.Bottom + 20.0
Stack View.Leading = Scroll View.Leading
Stack View.Trailing = Scroll View.Trailing
Stack View.Top = Scroll View.Top
Stack View.Bottom = Scroll View.Bottom
Stack View.Width = Scroll View.Width
Код: Stack View.Width = Scroll View.Width
это ключ.
Добавление некоторой новой перспективы для MacOS Catalyst. Так как приложения macOS поддерживают изменение размера окна, возможно, вы UIStackView
перейдете из состояния без прокрутки в состояние с прокруткой или наоборот. Здесь есть две тонкие вещи:
UIStackView
предназначен для всех областей, в которых это возможно.UIScrollView
попытается изменить размеры своих границ, чтобы учесть вновь приобретенную / потерянную область под панелью навигации (или панелью инструментов в случае приложений MacOS).Это, к сожалению, создаст бесконечный цикл. Я не очень знаком с ним UIScrollView
и его adjustedContentInset
, но из моего журнала в его layoutSubviews
методе я вижу следующее поведение:
UIScrollView
пытается уменьшить свои границы (так как нет необходимости в области под панелью инструментов).UIStackView
следующим образом.UIScrollView
не удовлетворены, и решили восстановить в более широких пределах. Это очень странно для меня, так как я вижу из журнала, чтоUIScrollView.bounds.height == UIStackView.bounds.height
.UIStackView
следующим образом.Мне кажется, что два шага решат проблему:
UIStackView.top
к UIScrollView.topMargin
.contentInsetAdjustmentBehavior
в .never
.Здесь меня интересует вертикально прокручиваемый вид с вертикально растущим UIStackView
. Для горизонтальной пары измените код соответствующим образом.
Надеюсь, это поможет кому-нибудь в будущем. Не удалось найти никого, кто бы упомянул об этом в Интернете, и мне потребовалось довольно много времени, чтобы понять, что произошло.