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

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

13 ответов


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

можно получить из 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)       
}

Я хотел сделать то же самое и наткнулся на это отличный пост. если вы хотите сделать это программно, используя anchor 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. Кнопки и представления будут загружаться, но scroll view не будет прокручивать. Это было решено путем добавления 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:

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

повторю:

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

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

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

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

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


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

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

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

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

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

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

  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)

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

при работе со стеком view

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

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

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

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


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

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

enter image description here


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