Возможно ли прокручивать UIStackView?


допустим, я добавил больше представлений в UIStackView, которые могут быть отображены, как я могу сделать UIStackView свиток?

13 129

13 ответов:

в случае, если кто-то ищет решение без кода я создал пример, чтобы сделать это в раскадровке, используя макет авто.

вы можете получить его от github.

в основном, чтобы воссоздать пример:

  1. создать UIScrollView, и установить свои ограничения.
  2. добавить UIStackView до UIScrollView
  3. установить ограничения: Leading,Trailing,Top & Bottom должно быть равны тем из UIScrollView
  4. установите равный Width ограничение между UIStackView и UIScrollView.
  5. установить ось = вертикальное выравнивание = заполнить, распределения = равный интервал, а интервал = 0 на UIStackView
  6. добавить UIViews до UIStackView
  7. выполнить

руководство по автоматической компоновке Apple включает в себя целый раздел работа с видами прокрутки. Некоторые соответствующие фрагменты:

  1. прикрепите верхнюю, нижнюю, переднюю и заднюю кромки представления содержимого к соответствующим кромкам представления прокрутки. Представление содержимого теперь определяет область содержимого представления прокрутки.
  2. (необязательно) чтобы отключить горизонтальную прокрутку, установите ширину представления содержимого равной ширине представления прокрутки. Просмотр содержимого заполняет прокрутка по горизонтали.
  3. (необязательно) чтобы отключить вертикальную прокрутку, установите высоту представления содержимого равной высоте представления прокрутки. Представление содержимого теперь заполняется вид прокрутки по горизонтали.

кроме того:

макет должен полностью определять размер представления содержимого (за исключением где определяется в шагах 5 и 6). ... Когда вид содержимого выше, чем вид прокрутки, вид прокрутки включает вертикальную прокрутку. Когда вид содержимого шире, чем вид прокрутки, вид прокрутки позволяет горизонтальную прокрутку.

чтобы подвести итог, представление содержимого прокрутки (в данном случае представление стека) должно быть прикреплено к его краям и имеют свою ширину и/или высоту в противном случае ограничены. Это означает, что содержимое вида стека должно быть ограничено (прямо или косвенно) в направлении(ах), в котором требуется прокрутка, что может означать добавление ограничения высоты к каждому виду например, в виде стека с вертикальной прокруткой. Ниже приведен пример того, как разрешить вертикальную прокрутку вида прокрутки, содержащего вид стека:

// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true

// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true

Как говорит Eik, 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

ограничения в верхнем голосовании здесь работали для меня, и я вставил изображение ограничений ниже, как создано в моей раскадровке.

я попал в две проблемы, хотя другие должны быть в курсе:

  1. после добавления ограничений, аналогичных тем, что были в принятом ответе, я бы получил красную ошибку автозапуска Need constraints for: X position or width. Это было решено путем добавления UILabel в качестве подвида представления стека.

    я добавляю подпанели программно, поэтому у меня изначально не было подвидов на раскадровке. Чтобы избавиться от ошибок автозапуска, добавьте подвиды в раскадровку, а затем удалите их при загрузке, прежде чем добавлять свои реальные подвиды и ограничения.

  2. Я изначально пытался добавить UIButtons в UIStackView. Кнопки и представления будут загружаться, но вид прокрутки не будет прокручивать. Это было решено путем добавления UILabels к виду стека вместо кнопок. Использование тех же ограничений, эта иерархия представлений с uilabels прокручивается, но UIButtons-нет.

    Я смущен этой проблемой, так как UIButtons do кажется, есть IntrinsicContentSize (используется в представлении стека). Если кто-нибудь знает, почему кнопки не работают, я хотел бы знать почему.

вот мой вид иерархии и ограничений, для справки:

constraints for stack view in scroll view[1]

просто добавьте это в viewdidload:

let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets

источник: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

Вы можете попробовать 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]; 
// ...

вот самое простое возможное объяснение:

  1. есть пустая полноэкранная сцена

  2. добавить прокрутки. Управление-перетащите из вида прокрутки на вид добавить слева-справа-сверху-снизу, все ноль.

  3. добавить представление стека в виде свитка. Управление-перетаскивание из вида стека в режиме прокрутки добавить слева-справа-сверху-снизу, все ноль.

  4. положите одну UILabel внутри представления стека.

для ясности сделайте цвет фона красным; установите высоту до 100, а в вашем стеке установите интервал до 20.

  1. теперь установите ширину UILabel:

    удивительно, управление-перетащить из UILabel в режиме прокрутки,не вид стека и выберите равная ширина.

повторю:

Не контролируйте перетаскивание из UILabel в Родитель UILabel ни для бабушек и дедушек. (Другими словами, перейдите к виду прокрутки, не переходите к виду стека.)

Это очень просто. Вот в чем секрет.

  1. далее должны нажмите на один UILabel, и вы должны буквально ударил копировать-вставить несколько раз. Это не работает только с одним пунктом. (Не нажимайте кнопку "дублировать", нажмите кнопку"копировать, а затем вставить".)

ты молодец. Это простой.

совет: попробуйте добавить новый элемент в представление стека, скажем, UIView (возможно, для использования в качестве пространства). Обратите внимание, что все идет не так. Ведь ты необходимо добавить высоту к каждому новому элементу (скажем, "100"). Каждый раз, когда вы добавляете новый элемент,вы должны дать ему высоту как-то.


другой способ взглянуть на это:

в приведенном выше, он говорит следующее: Удивительно, установите ширину UILabels на ширину вида прокрутки (не вид стека). Это прекрасно работает.

поочередно...

обратите внимание, что вид стека слева и справа прикреплен к его родительскому виду, виду прокрутки. Попробуйте это:

перетащите из вида стека в вид прокрутки и добавьте ограничение "ширина равна". Это кажется странным, потому что тебя уже прижали слева-справа, а вот как ты это делаешь. Каким бы странным это ни казалось, это секрет.

у вас есть два опции:

  1. Удивительно, но установите ширину UILabels на ширину ScrollView grandparent (не stackview родитель).

или

  1. Удивительно, но установите "ширину, равную" stackview для scrollview -хотя у вас все равно есть левый и правый края stackview, прикрепленные к scrollview.

чтобы быть ясным, сделайте один из эти методы, не делают оба.

Если у вас есть ограничение для центрирования вида стека по вертикали внутри вида прокрутки, просто удалите его.

пример для вертикального stackview / scrollview (с помощью EasyPeasy для 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)
]

просто убедитесь, что каждый из высоты вашего подвида определен!

  1. в первую очередь создайте свой вид, предпочтительно в чем-то вроде эскиза или получите идея того, что вы хотите в качестве прокручиваемого контента.

  2. после этого сделайте вид контроллера свободной формы (выберите из атрибута инспектор) и установите высоту и ширину согласно внутреннеприсущему содержанию размер вашего представления (выбирается из инспектора размеров).

  3. после этого в контроллере вида поместите вид прокрутки, и это логика, который я обнаружил, что работает почти все время в iOS (это может потребовать прохождения документации этого класса представления, которую можно получить с помощью команды + нажмите на этот класс или через googling)

    если вы работаете с двумя или более представлениями, то сначала начните с представления, которое было введено ранее или является более примитивным, а затем перейдите к представлению, которое было введено позже или более современно. Так вот с момента прокрутки вид был впервые, начните с сначала прокрутите представление, а затем перейдите к вид стека. Здесь поместите ограничения прокрутки до нуля во всех направлениях по отношению к его супер-виду. Поместите все свои представления в этот вид прокрутки, а затем поместите их в представление стека.

при работе с видом стека

  • сначала начните с основания вверх (подход снизу вверх), т. е., если у вас есть метки, текстовые поля и изображения в вашем представлении, то сначала выложите эти представления (внутри представления прокрутки) и после что положить их в стек.

  • после этого настроить свойство stack view. Если желаемое представление все еще не достигнуто, используйте другое представление стека.

  • Если все еще не достигнуто, то играйте с сопротивлением сжатию или приоритетом обнимания контента.
  • после этого добавьте ограничения в представление стека.
  • также подумайте об использовании пустого UIView в качестве вида наполнителя, если все вышеперечисленное не дает удовлетворительного результата результаты.

после создания представления поместите ограничение между представлением материнского стека и представлением прокрутки, в то время как представление дочернего стека ограничения с представлением материнского стека. Надеюсь, к этому времени он должен работать нормально, или вы можете получить предупреждение от Xcode с предложениями, прочитать, что он говорит, и реализовать их. Надеюсь, теперь вы должны иметь рабочий вид в соответствии с вашими ожиданиями:).

для вложенного или одиночного вида стека вид прокрутки должен быть установлен фиксированной ширины с корневым видом. Основной вид стека, который находится внутри вида прокрутки, должен иметь одинаковую ширину. [Мой вид прокрутки ниже вида игнорировать его]

Установите ограничение равной ширины между UIStackView и UIScrollView.

enter image description here

положите его в UIScrollView...