Я пытаюсь настроить самоконтроль при UICollectionViewCells
работе с Auto Layout, но я не могу заставить ячейки соответствовать размеру контента. У меня возникли проблемы с пониманием того, как размер ячейки обновляется из содержимого содержимого содержимого ячейки.
Вот настройки, которые я пробовал:
- Пользовательский
UICollectionViewCell
сUITextView
его в contentView. - Прокрутка для
UITextView
отключена. - Горизонтальное ограничение contentView: «H: | [_textView (320)]», т. Е. Закреплено
UITextView
слева от ячейки с явной шириной 320. - Вертикальное ограничение contentView: «V: | -0 - [_ textView]», то есть
UITextView
закреплено в верхней части ячейки. UITextView
Имеет набор высоты ограничение на константу которойUITextView
отчеты будут соответствовать тексту.
Вот как это выглядит с красным цветом фона ячейки, а UITextView
синим фона:
Я разместил проект, с которым я играл, на GitHub здесь .
Ответы:
Обновлено для Swift 5
preferredLayoutAttributesFittingAttributes
переименоватьpreferredLayoutAttributesFitting
и использовать авторазмерОбновлено для Swift 4
systemLayoutSizeFittingSize
переименован вsystemLayoutSizeFitting
Обновлено для iOS 9
Увидев, что мой GitHub-решение сломалось под iOS 9, у меня наконец-то появилось время полностью исследовать проблему. Сейчас я обновил репо, чтобы включить несколько примеров различных конфигураций для ячеек с самоконтролем. Мой вывод состоит в том, что самоконтролирующие клетки хороши в теории, но на практике беспорядочные. Слово предостережения при продолжении самоконтроля клеток.
TL; DR
Проверьте мой проект GitHub
Саморазмерные ячейки поддерживаются только в макете потока, поэтому убедитесь, что это то, что вы используете.
Есть две вещи, которые вам нужно настроить для работы с саморазмерными ячейками.
1. Установите
estimatedItemSize
наUICollectionViewFlowLayout
Макет потока станет динамичным по своей природе после того, как вы установите
estimatedItemSize
свойство.2. Добавить поддержку для определения размеров на вашем подклассе ячейки
Это входит в 2 аромата; Авто-макет или пользовательское переопределение
preferredLayoutAttributesFittingAttributes
.Создание и настройка ячеек с помощью Auto Layout
Я не буду вдаваться в подробности об этом, поскольку есть замечательный пост SO о настройке ограничений для ячейки. Просто будьте осторожны, что Xcode 6 сломал кучу вещей с iOS 7, поэтому, если вы поддерживаете iOS 7, вам нужно будет сделать что-то вроде того, чтобы убедиться, что autoresizingMask установлен в contentView ячейки, а границы contentView установлены как границы ячейки, когда ячейка загружена (т.е.
awakeFromNib
).Вы должны знать, что ваша ячейка должна быть более серьезно ограничена, чем ячейка табличного представления. Например, если вы хотите, чтобы ваша ширина была динамической, тогда ваша ячейка нуждается в ограничении высоты. Аналогично, если вы хотите, чтобы высота была динамической, вам понадобится ограничение ширины для вашей ячейки.
Внедрите
preferredLayoutAttributesFittingAttributes
в свою ячейкуКогда эта функция вызывается, ваше представление уже было настроено с содержимым (то
cellForItem
есть было вызвано). Предполагая, что ваши ограничения были установлены соответствующим образом, у вас может быть такая реализация:ПРИМЕЧАНИЕ В iOS 9 поведение немного изменилось, что может привести к сбоям в вашей реализации, если вы не будете осторожны (подробнее здесь ). При реализации
preferredLayoutAttributesFittingAttributes
вам необходимо убедиться, что вы изменяете фрейм атрибутов макета только один раз. Если вы этого не сделаете, макет будет вызывать вашу реализацию неопределенно долго и в конечном итоге вылетит. Одним из решений является кэширование вычисленного размера в вашей ячейке и аннулирование этого в любое время, когда вы повторно используете ячейку или меняете ее содержимое, как я сделал сisHeightCalculated
свойством.Испытайте свой макет
На этом этапе у вас должны быть «функционирующие» динамические ячейки в вашем collectionView. Я еще не нашел готового решения, достаточного для моих тестов, поэтому не стесняйтесь комментировать, если у вас есть. По-прежнему ощущается, что
UITableView
выигрывает битву за динамические размеры ИМХО.Предостережения
Помните, что если вы используете ячейки-прототипы для вычисленияtimateItemSize - это сломается, если ваша XIB использует классы размеров . Причина этого заключается в том, что при загрузке ячейки из XIB ее класс размера будет настроен с помощью
Undefined
. Это будет нарушено только в iOS 8 и выше, поскольку в iOS 7 класс размера будет загружаться в зависимости от устройства (iPad = обычный-любой, iPhone = компактный-любой). Вы можете либо установитьtimateItemSize без загрузки XIB, либо вы можете загрузить ячейку из XIB, добавить ее в collectionView (это установит traitCollection), выполнить макет, а затем удалить его из суперпредставления. В качестве альтернативы вы также можете заставить свою ячейку переопределятьtraitCollection
геттер и возвращать соответствующие черты. Тебе решать.Дайте мне знать, если я что-то пропустил, надеюсь, я помог и удачи в кодировании
источник
estimatedItemSize
приводит к сбоям - кажется, что в том, как автоматическая разметка пытается обработать UICollectionViewCell, есть огромная ошибка.В iOS10 есть новая константа, названная
UICollectionViewFlowLayout.automaticSize
(ранееUICollectionViewFlowLayoutAutomaticSize
), поэтому вместо этого:Вы можете использовать это:
Он имеет лучшую производительность, особенно когда ячейки в представлении вашей коллекции имеют постоянный вид
Доступ к макету потока:
Swift 5 Обновлено:
источник
collectionViewLayout
и просто проверить, что он имеет типUICollectionViewFlowLayout
Несколько ключевых изменений в ответе Даниэля Галаско устранили все мои проблемы. К сожалению, у меня недостаточно репутации, чтобы комментировать напрямую (пока).
На шаге 1 при использовании автоматического макета просто добавьте один родительский UIView в ячейку. ВСЕ внутри клетки должно быть подвидом родителя. Это ответило на все мои проблемы. Хотя XCode добавляет это для UITableViewCells автоматически, этого не происходит (но должно быть) для UICollectionViewCells. Согласно документам :
Затем полностью пропустите шаг 3. Это не нужно
источник
contentView
, XCode жалуется, что оно конфликтует с существующим свойством. Попытка добавить подпредставленияself.contentView
и установить ограничения для этого, а затем приложение вылетает.В iOS 10+ это очень простой двухэтапный процесс.
Убедитесь, что все содержимое вашей ячейки размещено в одном UIView (или внутри потомка UIView, такого как UIStackView, который значительно упрощает автоматическое расположение). Как и в случае динамического изменения размера UITableViewCells, для всей иерархии представления должны быть настроены ограничения, от самого внешнего контейнера до самого внутреннего представления. Это включает в себя ограничения между UICollectionViewCell и непосредственным дочерним видом
Поручите разметку вашего UICollectionView, чтобы размер автоматически
источник
UICollectionViewFlowLayout.automaticSize
что был переименован вUICollectionViewFlowLayoutAutomaticSize
.Добавить flowLayout для viewDidLoad ()
Кроме того, установите UIView в качестве mainContainer для вашей ячейки и добавьте в нее все необходимые представления.
Обратитесь к этому удивительному, умопомрачительному учебнику для дальнейшей справки: UICollectionView с авторазмером ячейки с использованием автоматического размещения в iOS 9 и 10
источник
РЕДАКТИРОВАНИЕ 19/19/19: Для iOS 13, просто используйте UICollectionViewCompositionalLayout с предполагаемой высотой. Не тратьте свое время на работу с этим неработающим API.
Поработав с этим в течение некоторого времени, я заметил, что изменение размера не работает для UITextViews, если вы не отключите прокрутку:
источник
тайна привязки contentView:
В одном странном случае это
не будет работать. Добавили четыре явных якоря к contentView, и это сработало.
и как обычно
в
YourLayout: UICollectionViewFlowLayout
Кто знает? Может помочь кому-нибудь.
кредит
https://www.vadimbulavin.com/collection-view-cells-self-sizing/
наткнулся на верхушку там - никогда не видел его больше нигде во всех тысячах статей об этом.
источник
Я сделал динамическую высоту ячейки представления коллекции. Вот репозиторий git hub .
И выясните, почему предпочитаемое значениеLayoutAttributesFittingAttributes вызывается более одного раза. На самом деле, он будет вызван как минимум 3 раза.
Изображение журнала консоли:
1-й предпочтительныйLayoutAttributesFittingAttributes :
LayoutAttributes.frame.size.height - текущий статус 57,5 .
2-й предпочитаемыйLayoutAttributesFittingAttributes :
Высота каркаса ячейки изменилась до 534,5, как и ожидалось. Но представление коллекции все еще нулевой высоты.
3-й предпочитаемыйLayoutAttributesFittingAttributes :
Вы можете видеть, что высота просмотра коллекции была изменена с 0 на 477 .
Поведение похоже на ручку прокрутки:
Сначала я думал, что этот метод вызывается только один раз. Поэтому я кодировал следующее:
Эта строка:
вызовет бесконечный цикл системного вызова и сбой приложения.
При любом изменении размера он будет снова и снова проверять все предпочтительные ячейки selectedLayoutAttributesFittingAttributes до тех пор, пока позиции каждой ячейки (т. Е. Кадры) больше не изменятся.
источник
В дополнение к ответам выше,
Просто убедитесь, что вы установили для свойства оценочного свойства UIollectionViewFlowLayout некоторый размер и не реализуете sizeForItem: atIndexPath делегата .
Вот и все.
источник
Если вы реализуете метод UICollectionViewDelegateFlowLayout:
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
Когда вы звоните
collectionview performBatchUpdates:completion:
,sizeForItemAtIndexPath
вместо размера будет использоваться высотаpreferredLayoutAttributesFittingAttributes
.Процесс рендеринга
performBatchUpdates:completion
будет проходить через метод,preferredLayoutAttributesFittingAttributes
но он игнорирует ваши изменения.источник
Кому бы это ни помогло,
У меня был этот неприятный сбой, если
estimatedItemSize
был установлен. Даже если я вернул 0 вnumberOfItemsInSection
. Таким образом, сами ячейки и их автоматическое расположение не были причиной сбоя ... CollectionView просто сбой, даже если он пуст, просто потому, чтоestimatedItemSize
был настроен для самостоятельного определения размера.В моем случае я реорганизовал свой проект, с контроллера, содержащего collectionView, на collectionViewController, и он работал.
Пойди разберись.
источник
collectionView.collectionViewLayout.invalidateLayout()
послеcollectionView.reloadData()
.Для всех, кто попробовал все без удачи, это единственное, что заставило меня работать. Для многострочных меток внутри ячейки попробуйте добавить эту волшебную строку:
Больше информации: здесь
Ура!
источник
Приведенный выше пример метода не компилируется. Вот исправленная версия (но не проверенная относительно того, работает ли она.)
источник
Обновите больше информации:
Если вы используете
flowLayout.estimatedItemSize
, предложите использовать iOS8.3 более поздней версии. До iOS8.3 он вылетит[super layoutAttributesForElementsInRect:rect];
. Сообщение об ошибке*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Во-вторых, в версии iOS8.x,
flowLayout.estimatedItemSize
не будет работать настройка вставки различных разделов. то есть функция:(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:
.источник
Решение состоит из 4 важных шагов:
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
contentView
ее по краям ячейки, поскольку онаcontentView
предотвращает автоматическое изменение размера, учитывая, что для нее не включена автоматическая разметка.collectionView(:cellForItemAt:)
чтобы ограничить ширину contentView шириной collectionView.Это происходит следующим образом; мы установим ячейку
maxWidth
переменной ширину CollectionView по адресуcollectionView(:cellForItemAt:)
и вmaxWidth
«SdidSet
метода мы установим widthAnchor.constant в MaxWidth.Поскольку вы хотите включить самоопределение UITextView, у него есть дополнительный шаг к;
4. Рассчитайте и установите значение heightAnchor.constant для UITextView.
Таким образом, всякий раз , когда ширина contentView установлена , мы будем корректировать высоту UITextView вместе в
didSet
оmaxWidth
.Внутри UICollectionViewCell:
Эти шаги принесут вам желаемый результат. Вот полная суть
Спасибо Вадиму Булавину за его ясное и понятное сообщение в блоге - Самостоятельная подборка элементов View Collection: пошаговое руководство
источник
Я пытался использовать,
estimatedItemSize
но при вставке и удалении ячеек было много ошибок, если ониestimatedItemSize
не были точно равны высоте ячейки. я перестал устанавливатьestimatedItemSize
и реализовал динамические ячейки, используя прототип ячейки. вот как это делается:создайте этот протокол:
реализовать этот протокол в вашем обычае
UICollectionViewCell
:Теперь сделайте так, чтобы ваш контроллер соответствовал
UICollectionViewDelegateFlowLayout
и имел в этом поле:она будет использоваться в качестве ячейки-прототипа для привязки данных, а затем для определения того, как эти данные повлияли на измерение, которое вы хотите динамически
наконец,
UICollectionViewDelegateFlowLayout's
collectionView(:layout:sizeForItemAt:)
должно быть реализовано:и это все.
collectionView(:layout:sizeForItemAt:)
Таким образом, возвращая размер ячейки, я не могу ее использоватьestimatedItemSize
, а вставка и удаление ячеек работает отлично.источник