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

406

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

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

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

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

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

Например, Trailing Space для: Superview Equals: 25

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

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

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

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

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

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

Помоги мне Оби-Ван Кеноби! Почему неоднозначный макет? Почему неуместное мнение?

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

Изображение 51

  • 8
    Попробуйте разместить UILabel в представлении содержимого, затем установите задний край метки для представления содержимого (обычный UIView). Это видео может вам очень помочь: youtube.com/watch?v=PgeNPRBrB18&feature=youtu.be
  • 1
    Отличное видео, но оно не исправило предупреждения для меня. :(
Показать ещё 5 комментариев
Теги:
autolayout
uiscrollview
interface-builder
ios7

26 ответов

934
Лучший ответ

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

Поэтому я просто разобрался в этом:

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

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

Закончено.

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

Обновить:

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

  • 112
    Это великолепно! Центр X и Y был ключевым элементом!
  • 29
    Почти идеально, за исключением того, что представление прокрутки больше не может угадать длину вашего контента и соответственно изменить его размер, это contentSize, чтобы соответствовать объектам внутри. У меня есть представление таблицы внутри contentView, высота которого изменяется (через ограничение), и представление прокрутки не позволяет мне прокручивать.
Показать ещё 34 комментария
93

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

  • 29
    Спасибо за ваш ответ! Если я вас правильно понимаю, вы добьетесь устранения ошибки, закрепив каждое подпредставление в ScrollView сверху и снизу. Однако в этом нет необходимости. Вам просто нужно убедиться, что есть способ создать непрерывную линию ограничений сверху вниз для прокрутки. [-XXX] Надеюсь, это было понятно;>
  • 1
    Как решить проблему, если представление имеет переменную высоту? Как мне установить ограничения, чтобы scrollview мог рассчитать размеры?
Показать ещё 10 комментариев
63

Ответьте на мой вопрос с ответом UIScrollView + Centered View + Ambigous Scrollable Content Size + много размеров iPhone.

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

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

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

Изображение 1624

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

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

Важно: вам нужно добавить ограничения трейлинг и/или снизу. Не "ведущий и верхний" - он не работает!

Изображение 1625

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

P.S.

Согласно логике - это действие должно вызывать "конфликтующие ограничения". Но нет!

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

  • 0
    Отличный совет! В итоге я просто создал ограничение по нижнему краю и установил приоритет на средний или низкий
  • 0
    трейлинг или низ сделали магию, странно.
Показать ещё 1 комментарий
43

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

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

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

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

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

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

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

  • 2
    Согласовано - я думаю, что добавление представления контейнера является лучшим и наиболее приемлемым решением.
  • 0
    Это решение будет работать, когда у вас нет навигационной панели для управления.
23

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

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

Изображение 1626

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

  • 1
    Вышеприведенное почти сработало для меня, так как я беспокоюсь о 3-х различных значениях ширины экрана (4/5, 6, 6+). Я настроил представление содержимого и представление прокрутки на одинаковую ширину. Вы правы, это дубликат, так как я уже сказал, что в представлении содержимого должно быть 0 начальных и конечных пробелов.
  • 7
    Вы можете установить равные ограничения ширины и высоты от представления содержимого до представления с прокруткой вместо постоянных значений. Это будет работать на всех разрешениях.
Показать ещё 5 комментариев
14

iOS 12, Swift 4

Самый простой способ с помощью autolayout:

  1. Добавьте UIScrollView и прикрепите его 0,0,0,0 к 0,0,0,0 (или желаемому размеру)
  2. Добавьте UIView в ScrollView, прикрепите его 0,0,0,0 ко всем 4 сторонам и 0,0,0,0 по horizontally и vertically.
  3. В инспекторе размеров измените bottom и align center Y приоритет по align center Y на 250. (для горизонтальной прокрутки измените trailing и align center X)
  4. Добавьте все представления, которые вам нужны, в это представление. Не забудьте установить нижнее ограничение для самого нижнего вида.
  • 0
    Мне не удалось установить высоту содержимого scrollview, но это работает. :)
  • 0
    Подсказка: у меня это сработало, только если я удалил центр по горизонтали и вертикали и заменил его равной шириной (scrollView + view внутри scrollView) И добавил высоту, основанную на содержимом, что означает, что последнему элементу представления необходимо ограничение снизу. Смотрите здесь для получения дополнительной информации: stackoverflow.com/a/54577278/5056173
Показать ещё 1 комментарий
14

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

Для просмотра содержимого вам нужно установить ограничения для ведущих/конечных/верхних/нижних пробелов для прокрутки и , это не изменит рамки представления контента, например: Изображение 1627

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

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

6

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

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

3

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

Изображение 1628

  • 3
    Это просто удалит предупреждение и ничего не сделает для решения проблемы.
  • 0
    Вы. являются. мой. герой. Не осознавал, что это существовало, и я рад найти его! Я пробовал «Проверять только позицию», которую вы ожидаете, я не знаю, проверять только позицию, но нет, она также допускает эту проблему с «размером контента». Должен пойти с "Никогда не проверять". Спасибо!
3

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

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

Изображение 1629

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

2

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

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

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

2

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

1

Я решил эту проблему для своего взгляда, используя "Разрешить автоматические макеты"> "Добавить отсутствующие ограничения" для Selected View Изображение 1630

Следующие две проблемы решают мою проблему:

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

в котором: trailing, bottom - конечная нижняя часть UIScrollView

  • 0
    Это сработало для меня, добавив ограничение «снизу». Теперь, когда я думаю об этом, это имеет смысл.
1

Это техническое примечание полезно.

pure auto layout approach, упомянутый в статье, также может быть выполнен в конструкторе интерфейса.

1

Я сделал видео на youTube
Прокрутить StackViews, используя только Storyboard в Xcode

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

Вид внутри scrollView -

  • не имеет никакого внутреннего содержимого. Размер (например, UIView)
  • имеет собственное внутреннее содержимое. Размер (например, UIStackView)

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

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

  • Равная ширина для прокрутки (для остановки прокрутки по горизонтали)

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

Изображение 1631


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

Изображение 1632

1

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

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

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

0

Быстрый подход 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

Установите ViewController (тот, у которого есть UIScrollView) размер Freeform в инспекторе размеров в Interface Builder, и все должно работать.

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

0

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

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

0

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

Изображение 1634

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

Изображение 1635

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

0

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

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

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

0

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

Что подавляло ошибки и предупреждения Storyboard для меня, это установить собственный размер прокрутки и представление содержимого (в моем случае, stackview) для Placeholder. Этот параметр можно найти в инспекторе размера в раскадровке. И в нем говорится: настройка размера внутреннего содержимого времени разработки влияет только на представление при редактировании в Interface Builder. У представления не будет такого внутреннего размера содержимого во время выполнения.

Итак, я думаю, мы не ошибаемся, установив это.

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

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

0

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

  • Вид (SuperView)
  • ScrollView 0,0,600,600
  • UIView внутри ScrollView: 0,0,600,600
  • UIView содержит изображение, метку

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

Выберите "Вид" (1) и "Вид" (3), заданный одинаково по высоте и весу. Он решил мою проблему.

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

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

0

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

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

UIScrollView добавляется в основной контроллер представления.

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

Изображение 1633

-2

Я думаю, что это 10-секундная работа. Я заметил это в XCode 7.3 и сделал видео на нем. Проверьте здесь:

https://www.youtube.com/watch?v=yETZKqdaPiI

Все, что вам нужно сделать, добавьте subview к UIScrollView с одинаковой шириной и высотой. Затем выберите ViewController и нажмите Reset to suggested constraint. Пожалуйста, проверьте видео для четкого понимания.

Спасибо

-3

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню