Оновлено для Swift 5
preferredLayoutAttributesFittingAttributes
перейменовано на preferredLayoutAttributesFitting
та використовувати автоматичне розмір
Оновлено для Swift 4
systemLayoutSizeFittingSize
перейменований на systemLayoutSizeFitting
Оновлено для iOS 9
Побачивши перерву в GitHub під iOS 9, я нарешті отримав час повністю вивчити проблему. Зараз я оновив репо, щоб включити кілька прикладів різних конфігурацій для самостійного розміру комірок. Мій висновок полягає в тому, що самостійно розміщувати клітини теоретично, але на практиці безладно. Слово обережності, коли ви продовжуєте самостійно розміщувати клітини.
TL; DR
Перегляньте мій проект GitHub
Осередки розміщення з розмірами підтримуються лише макетом потоку, тому переконайтеся, що ви використовуєте.
Існує дві речі, які потрібно налаштувати для самостійного розміщення осередків для роботи.
1. Встановити estimatedItemSize
наUICollectionViewFlowLayout
Макет потоку набуде динамічного характеру, коли ви встановите estimatedItemSize
властивість.
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
2. Додайте підтримку розміру на своєму підкласі комірок
Це в 2 ароматах; Auto-Layout або призначене для користувача перевизначення preferredLayoutAttributesFittingAttributes
.
Створіть та налаштуйте комірки за допомогою автоматичного макета
Я не буду докладно розповідати про це, оскільки існує геніальний повідомлення про налаштування обмежень для комірки. Просто будьте обережні, що Xcode 6 зламав купу речей з iOS 7, тому якщо ви підтримуєте iOS 7, вам потрібно буде виконати такі дії, як переконатися, що autoresizingMask встановлено на contentView комірки та що межі contentView встановлені як межі комірки, коли клітинка завантажена (тобто awakeFromNib
).
Те, що вам потрібно знати, - це те, що ваша клітина повинна бути серйозніше обмежена, ніж комірка таблиці. Наприклад, якщо ви хочете, щоб ваша ширина була динамічною, ваша клітина потребує обмеження по висоті. Так само, якщо ви хочете, щоб висота була динамічною, вам знадобиться обмеження ширини для вашої комірки.
Реалізуйте preferredLayoutAttributesFittingAttributes
у вашій користувацькій комірці
Коли ця функція викликається, ваш погляд вже налаштовано на вміст (тобто cellForItem
був викликаний). Якщо припустити, що ваші обмеження були встановлені належним чином, у вас може бути така реалізація:
//forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
ПРИМІТКА На iOS 9 поведінка трохи змінилася, що може спричинити збої у вашій програмі, якщо ви не будете обережні (див. Більше тут ). Під час реалізації preferredLayoutAttributesFittingAttributes
вам потрібно переконатися, що ви змінюєте рамку атрибутів макета лише один раз. Якщо цього не зробити, макет викликатиме вашу реалізацію нескінченно і врешті-решт завершиться збоєм. Одним із варіантів є кешування обчисленого розміру у вашій комірці та визнання його недійсним у будь-який час, коли ви повторно використовуєте клітинку або зміните її вміст, як я це зробив із isHeightCalculated
властивістю.
Спробуйте свій макет
На цьому етапі у вашому collectionView повинні бути "функціонуючі" динамічні комірки. Я ще не знайшов рішення, яке випускається з коробки, достатньо під час моїх тестів, тому сміливо коментуйте, якщо у вас є. Він все ще відчуває, як UITableView
виграє битву за динамічне розмір ІМХО.
Коваджі
Майте на увазі, що якщо ви використовуєте комірки прототипу для обчислення оціненогоItemSize - це порушиться, якщо ваш XIB використовує класи розмірів . Причиною цього є те, що коли ви завантажуєте свою клітинку з XIB, її клас розмірів буде налаштований Undefined
. Це буде порушено лише на iOS 8 і вище, оскільки на iOS 7 клас розмірів завантажуватиметься на основі пристрою (iPad = Звичайний-будь-який, iPhone = Компактний-Будь-який). Ви можете або встановити очікуванийItemSize, не завантажуючи XIB, або можете завантажити клітинку з XIB, додати її до collectionView (це встановить traitCollection), виконати макет і потім видалити його з нагляду. Крім того, ви також можете змусити вашу клітинку замінити traitCollection
геттер і повернути відповідні риси. Тобі вирішувати.
Дайте мені знати, якщо я щось пропустив, сподіваюся, що я допоміг і вдало кодуйте