it-swarm.com.ru

UIScrollView прокручиваемый размер содержимого неоднозначность

Товарищи разработчики, У меня проблемы с AutoLayout в Интерфейсном Разработчике (Xcode 5/iOS 7) . Это очень просто и важно, поэтому я думаю, что все должны знать, как это работает правильно. Если это ошибка в Xcode, то она критическая!

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

>UIViewController
>> UIView
>>>UIScrollView
>>>>UILabel (or any other comparable UIKit Element)

UIScrollView имеет сплошные ограничения, например, 50 px со всех сторон (без проблем) . Затем я добавляю ограничение Top Space в UILabel (без проблем) (и я даже могу прикрепить высоту/ширину метки, ничего не меняя , но должен быть излишним из-за собственного размера метки)

Проблема начинается, когда я добавляю конечное ограничение к UILabel:

Например, Trailing Space для: Superview Равно: 25

Теперь появляются два предупреждения - и я не понимаю, почему:

A) Неоднозначность прокручиваемого размера контента (Вид прокрутки имеет неоднозначную высоту/ширину прокручиваемого контента)

B) Смещенные представления (ожидаемая метка: x = -67 Фактическая: x = 207

Я сделал этот минимальный пример в новом проекте, который вы можете загрузить, и приложил скриншот. Как вы можете видеть, Interface Builder ожидает, что Label будет находиться за границей UIScrollView (оранжевый пунктирный прямоугольник). Обновление фрейма метки с помощью инструмента устранения проблем перемещает его прямо туда.

Обратите внимание: если вы замените UIScrollView на UIView, поведение будет таким, как ожидается (рамка метки правильная и соответствует ограничению). Так что, кажется, либо проблема с UIScrollView, либо я упускаю что-то важное.

Когда я запускаю приложение без обновления фрейма метки, как это было предложено IB, оно очень хорошо позиционируется, именно там, где и должно быть, и UIScrollView прокручивается .. Если я обновляю фрейм, метка исчезает, а UIScrollView не прокручивает.

Помоги мне Оби-Ван Кеноби! Почему неоднозначное расположение? Почему неуместный вид?

Вы можете скачать пример проекта здесь и попробовать, если сможете выяснить, что происходит: https://github.com/Wirsing84/AutoLayoutProblem

Illustration of the problem in Interface Builder

417
Wirsing

ПРИМЕЧАНИЕ: на iOS> 10.0 это не было проверено; поэтому решение может быть неполным в определенных ситуациях.

Так что я просто разобрался таким образом:

  1. Внутри UIScrollViewadd a UIView (мы можем назвать это contentView);

  2. В этом contentView, установите верхнее, нижнее, левое и правое поля равными 0 (конечно, из scrollView, который является superView); Установите также выравнивание по центру по горизонтали и вертикали;

Закончено.

Теперь вы можете добавить все свои представления в эту contentView, и размер contentSize для scrollView будет автоматически изменен в соответствии с contentView.

Обновление:

Некоторые особые случаи описаны в этом видео опубликованном @Sergio в комментариях ниже.

918
Matteo Gobbi

Эта ошибка заняла у меня какое-то время, чтобы отследить, сначала я попытался закрепить размер ScrollView, но в сообщении об ошибке четко указано «размер контента». Я удостоверился, что все, что я прикрепил от вершины ScrollView, было также прикреплено к основанию. Таким образом, ScrollView может рассчитать высоту своего содержимого, найдя высоту всех объектов и ограничений. Это решило неоднозначную высоту содержимого, ширина была примерно одинаковой ... Изначально у меня было большинство элементов X по центру в ScrollView, но я также должен был прикрепить объекты к стороне ScrollView. Мне это не нравится, потому что iPhone6 ​​может иметь более широкий экран, но он уберет ошибку «неоднозначная ширина контента».

91
self.name

Это ответ на мой вопрос, на который он сам ответил UIScrollView + Центрированный вид + Неоднозначный прокручиваемый размер контента + множество размеров iPhone .

Но это полностью покрывает и ваше дело!

Итак, вот начальное состояние для простейшего случая:

  1. scrollView с 0 ограничениями для всех ребер
  2. Кнопка по центру по горизонтали и вертикали с фиксированными ограничениями ширины и высоты
  3. И, конечно же, раздражающие предупрежденияHas ambiguous scrollable content width и Has ambiguous scrollable content height.

1

Все, что нам нужно сделать, это:

  • Добавьте 2 дополнительных ограничения, например, «0» для пробела trailing и/или bottom для нашего представления (посмотрите на пример на скриншоте ниже).

Важно: вы должны добавить ограничения trailing и/или bottom. Не "ведущий и топ" - это не работает!

2

Вы можете проверить это в моем примере проекта , который демонстрирует, как решить эту проблему.

P.S.

Согласно логике - это действие должно вызывать «противоречивые ограничения». Но нет!

Я не знаю, почему это работает и как XCode определяет, какое ограничение является более приоритетным (потому что я не устанавливаю приоритет для этих ограничений) ... Я буду благодарен, если кто-то объяснит, почему это работает в комментариях ниже.

60
skywinder

Вам необходимо создать UIView как подпредставление UIScrollView, как описано ниже:

  • UIViewController
  • UIView 'Главный вид'
    • UIScrollView
      • UIView 'Просмотр контейнера'
        • [Ваш контент]

Второй шаг - сделать ограничения UIScrollView. Я сделал это с верхним, нижним, ведущим и конечным ограничениями для его superView.

Затем я добавил ограничения для контейнера UIScrollView и вот где начинается проблема. Когда вы накладываете те же ограничения (сверху, снизу, впереди и сзади), раскадровка выдает предупреждение: 

«Имеет неоднозначную ширину прокручиваемого содержимого» и «Имеет неоднозначную высоту прокручиваемого содержимого»

Продолжайте использовать те же ограничения, что и выше, и просто добавьте ограниченияEqual HeightиEqual Widthк вашему представлению контейнера относительно основного вида и не к вашей UIScrollView , Другими словами, ограничения Контейнерного Представления связаны с суперпредставлением UIScrollView.

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

45
Thiago Monteiro

Я наконец понял это, надеюсь, это легче понять. 

Вы часто можете обойти это предупреждение, добавив базовый UIView к просмотру прокрутки как «представление контента», как они упоминали, и сделайте его равным размеру вашего прокрутки и, на этом представлении контента, установите эти 6 параметров. 

 enter image description here

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

24
William T.

iOS 12, Swift 4

Самый простой способ с использованием autolayout:

  1. Добавьте UIScrollView и прикрепите 0,0,0,0 к суперпредставлению (или желаемому размеру)
  2. Добавьте UIView в ScrollView, прикрепите 0,0,0,0 ко всем 4 сторонам и отцентрируйте horizontally и vertically.
  3. В инспекторе размера измените приоритет bottom и align center Y на 250. (для горизонтальной прокрутки измените trailing и align center X)
  4. Добавьте все представления, которые вам нужны, в это представление. Не забудьте , чтобы установить нижнее ограничение для самого нижнего вида.
20
Đorđe Nilović

Я знаю, что могу опоздать, но следующее решение решает такие проблемы без дополнительного кода , просто используя раскадровки:

Для просмотра контента вам нужно установить ограничения для начальных/конечных/верхних/нижних пробелов в scrollview и это не изменит фрейм просмотра контента , например: enter image description here

Конечно, вам нужно создать дополнительные ограничения для представления содержимого, чтобы представление прокрутки могло знать размер содержимого. Например, установите фиксированную высоту и центр х.

Надеюсь это поможет.

14
Borzh

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

http://samwize.com/2014/03/14/how-to-use-uiscrollview-with-autolayout/

6
Mike Simz

Для меня добавление contentView не сработало, как предлагалось. Кроме того, это создает накладные расходы из-за добавленного представления (хотя я не считаю это большой проблемой). Для меня лучше всего было просто отключить проверку неоднозначности для моей scrollView. Все хорошо выглядит, так что я думаю, что это нормально в простых случаях, таких как мой. Но имейте в виду, что если другие ограничения для вашего scrollView прервутся, Interface-Builder не предупредит вас об этом.

 enter image description here

3
Nick Podratz

См. Ниже: представление контента в вертикальном и горизонтальном централизованном представлении scrollview . Вы получили ошибку неоднозначности, всегда убедитесь, что два добавленных в представление scrollview из вашего представления содержимого: 1) .button space to container.2) конечный пробел к ограничению, который выделен в Скриншот, 

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

 enter image description here

это может помочь вам.

3
Ravi H Malviya

@Matteo Gobbi ответ идеален, но в моем случае прокрутка не может прокручиваться, я удаляю " выровнять центр Y " и добавляю " height> = 1 ", прокрутка становится прокручиваемой 

2
ygweric

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

Остальные все ограничения такие же, как определено выше. Scrollview заботится только о том, чтобы получить максимальную высоту из его представления содержимого, и мы устанавливаем его как нижнее ограничение последнего представления, что означает, что scrollview автоматически изменит смещение содержимого.

В моем случае последнее представление было UILable без свойства lines = 0 (которое автоматически регулирует его высоту в зависимости от его содержимого), поэтому оно динамически увеличивало высоту uilable, и в итоге наша прокручиваемая область увеличивается, поскольку нижний макет uilable выравнивается по низу нашего представления содержимого, что заставляет scrollview увеличивать смещение контента. 

2
Siddhesh Mahadeshwar

Используя contentView (UView) в качестве контейнера внутри UIScrollView, придерживайтесь краев (top, bottom, trailing, leading) superview (UIScrollView) и contentView, чтобы иметь equalwidth и equalheight для superview. Это ограничения. И вызов метода:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.scrollView.contentSize = self.contentView.frame.size;
}

Решенные проблемы для меня.

1
Spiridon Kopicl

Я решил эту проблему для своего вида, используя «Устранение проблем с автоматической компоновкой»> «Добавить отсутствующие ограничения» для выбранного представления  enter image description here

Следующие два ограничения решают мою проблему:

trailing = Stack View.trailing - 10
bottom = Stack View.bottom + 76

в котором: трейлинг, в нижней части трейлинг, в нижней части UIScrollView

1
Linh Dao

Я сделал видео на YouTube 
Прокрутка StackViews с использованием только раскадровки в Xcode

Я думаю, что 2 вида сценариев могут появиться здесь.

Вид внутри scrollView -

  1. не имеет встроенного содержимого Размер (например, UIView)
  2. имеет свой собственный размер содержимого (например, UIStackView)

Для просмотра с вертикальной прокруткой в ​​обоих случаях необходимо добавить следующие ограничения:

  1. 4 ограничения сверху, слева, снизу и справа.

  2. Равная ширина прокрутки (чтобы остановить горизонтальную прокрутку)

Вам не нужны никакие другие ограничения для представлений, которые имеют собственную высоту содержимого.

 enter image description here


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

 enter image description here

1
Warif Akhand Rishi

Установите размер ViewController (тот, который содержит UIScrollView) на Freeform в Инспекторе размеров в Интерфейсном Разработчике, и все должно работать.

Настройка произвольной формы в Инспекторе размеров в Интерфейсном Разработчике для содержащего UIViewcontroller

0
nico

Вертикальная прокрутка

  1. Добавьте UIScrollView с ограничениями 0,0,0,0 для суперпредставления.
  2. Добавьте UIView в ScrollView с ограничениями 0,0,0,0 для суперпредставления.
  3. Добавьте такое же ограничение ширины для UIView в UIScrollView.
  4. Добавьте высоту в UIView.
  5. Добавьте элементы с ограничениями в UIView.
  6. Для элемента, ближайшего к нижней части, убедитесь, что он имеет ограничение к нижней части UIView.
0
BitCon

Вы просто должны убедиться, что есть способ сделать непрерывный линия ограничений сверху вниз прокрутки . [-X-Х-Х]

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

0
johnnyMac

[протестировано в XCode 7.2 и для iOS 9.2]

Что подавляло ошибки и предупреждения раскадровки для меня, так это установив внутренний размер представления прокрутки и представления содержимого (в моем случае, стека) в Placeholder. Этот параметр находится в Инспекторе размеров в Раскадровке. И это говорит - Установка внутреннего размера времени разработки влияет только на представление при редактировании в Интерфейсном Разработчике. Представление не будет иметь этот собственный размер содержимого во время выполнения.

Так что, полагаю, мы не ошибемся, установив это. 

Примечание. В раскадровке я закрепил все края скроллвью в суперпредставлении и все края стека в скроллвью. В моем коде я установил translatesAutoresizingMaskIntoConstraints как false как для просмотра прокрутки, так и для просмотра стека. И я не упомянул размер контента. Когда динамический рост стека увеличивается, ограничения, установленные в раскадровке, обеспечивают возможность прокрутки стека. 

Предупреждение о раскадровке сводило меня с ума, и я не хотел центрировать вещи по горизонтали или вертикали только для того, чтобы подавить предупреждение. 

0
gtl_pm

Свифт 4+ подход:

1) Установите UIScrollView верхний, нижний, левый и правый поля на 0

2) Внутри UIScrollView добавьте UIView и установите верхние, нижние, ведущие, конечные поля равными 0 (равным полям UIScrollView). 

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

private func setupConstraints() {
    // Constraints for scrollView
    scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    // Constraints for containerView
    containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
    containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
    containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
    let heightConstraint = containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
    heightConstraint.priority = UILayoutPriority(rawValue: 250)
    heightConstraint.isActive = true
}
0
Gentian Sadiku

Я получаю ту же ошибку .. я сделал следующее

  1. Просмотр (SuperView)
  2. ScrollView 0,0 600 600
  3. UIView внутри ScrollView: 0,0 600 600
  4. UIView содержит вид изображения, метку

Теперь добавьте начальные/конечные/верхние/нижние для scrollView (2), а затем UIView (3).

Выберите View (1) и View (3), чтобы установить одинаковый рост и вес. Это решило мою проблему.

Я сделал видео, которое поможет:

https://www.youtube.com/watch?v=s-CPN3xZS1A

0
Vinod Joshi

Что я сделал, это создал отдельный вид контента, как показано здесь. 

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

UIScrollView добавлен в контроллер основного вида.

Программно я добавляю contentView, который связан через IBOutlet к классу и устанавливаю contentView UIScrollView.

UIScrollView with ContentView via Interface Builder

0
Vlad

Если кто-то испытывает поведение, когда вы замечаете полосу прокрутки на правильных прокрутках, но содержимое не перемещается, этот факт, вероятно, стоит рассмотреть:

Вы также можете использовать ограничения между содержимым представления прокрутки и объектами за пределами представления прокрутки, чтобы обеспечить фиксированную позицию для содержимого представления прокрутки, в результате чего содержимое будет отображаться в виде прокрутки.

Это из Apple документация . Например, если вы случайно прикрепили верхний ярлык/кнопку/изображение/вид к виду за пределами области прокрутки (может быть, заголовок или что-то чуть выше scrollView?) Вместо contentView, вы бы заморозили весь свой contentView на месте.

0
Dave G

Как упоминалось в предыдущих ответах, вы должны добавить пользовательский вид в представление прокрутки:

 The custom view is the ContentView marked in the image

Добавьте все ваши подпредставления в представление содержимого . В какой-то момент вы увидите, что представление содержимого прокрутки имеет неоднозначное предупреждение о размере содержимого, вам следует выбрать представление содержимого и нажать кнопку «Устранить проблемы с автоматическим макетом» (в правом нижнем углу). макета IB) и выберите параметр «Добавить отсутствующие ограничения».

 enter image description here

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

0
supergegs