Как определить высоту UICollectionView с FlowLayout
У меня есть UICollectionView
с UICollectionViewFlowLayout
, и я хочу рассчитать его размер содержимого (для возврата в intrinsicContentSize
, необходимого для настройки его высоты с помощью AutoLayout).
Проблемы: Даже если у меня есть фиксированная и равная высота для всех ячеек, я не знаю, сколько "строк" /строк у меня есть в UICollectionView
. Я также не могу определить этот счет по количеству элементов в моем источнике данных, поскольку ячейки, представляющие элементы данных, различаются по ширине, поэтому число элементов, которые у меня есть, в одной строке UICollectionView
.
Поскольку я не мог найти никаких намеков на эту тему в официальной документации, а googling не привел меня дальше, любая помощь и идеи были бы очень оценены.
Ответы
Ответ 1
Вау! По некоторым причинам, после нескольких часов исследований, я нашел довольно простой ответ на мой вопрос: я полностью искал не то место, прорывая всю документацию, которую я мог найти на UICollectionView
.
Простое и простое решение лежит в базовом макете: просто назовите collectionViewContentSize
своим свойством myCollectionView.collectionViewLayout
, и вы получите высоту и ширину содержимого как CGSize
. Это так просто.
Ответ 2
Если вы используете Автомакет, вы можете создать подкласс UICollectionView
Если вы используете приведенный ниже код, вам не нужно указывать какие-либо ограничения высоты для представления коллекции, так как это зависит от содержимого представления коллекции.
Ниже приведена реализация:
@interface DynamicCollectionView : UICollectionView
@end
@implementation DynamicCollectionView
- (void) layoutSubviews
{
[super layoutSubviews];
if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize]))
{
[self invalidateIntrinsicContentSize];
}
}
- (CGSize)intrinsicContentSize
{
CGSize intrinsicContentSize = self.contentSize;
return intrinsicContentSize;
}
@end
Ответ 3
В viewDidAppear
вы можете получить его:
float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;
Возможно, когда вы перезагружаете данные, вам нужно вычислить новую высоту с новыми данными, тогда вы можете получить ее:
добавьте наблюдателя для прослушивания, когда ваши CollectionView
закончили перезагружать данные в viewdidload
:
[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];
Затем добавьте следующую функцию, чтобы получить новую высоту или сделать что-либо после завершения загрузки коллекции:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//Whatever you do here when the reloadData finished
float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;
}
И не забудьте удалить наблюдателя:
[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];
Ответ 4
user1046037 ответ в Swift...
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if bounds.size != intrinsicContentSize() {
invalidateIntrinsicContentSize()
}
}
override func intrinsicContentSize() -> CGSize {
return self.contentSize
}
}
Ответ 5
Свифт 3 для пользователя1046037 ответ
import UIKit
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return contentSize
}
}
Ответ 6
Swift 4
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return collectionViewLayout.collectionViewContentSize
}
}
Ответ 7
Слишком поздно, чтобы ответить на этот вопрос, но я недавно пережил этот вопрос.
@lee выше ответ помогите мне многое, чтобы получить мой ответ. Но этот ответ ограничен objective-c, и я работал в быстро.
@lee Что касается вашего ответа, позвольте мне позволить быстрому пользователю решить эту проблему легко. Для этого выполните следующие шаги:
Объявить переменную CGFloat
в разделе объявления:
var height : CGFloat!
В viewDidAppear
вы можете получить его:
height = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height
Может быть, когда вы reload
данных, тогда вам нужно вычислить новую высоту с новыми данными, тогда вы можете получить ее: addObserver
для прослушивания, когда ваши CollectionView
закончили перезагружать данные в viewWillAppear
:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
....
....
self.shapeCollectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old, context: nil)
}
Затем добавьте следующую функцию, чтобы получить новую высоту или сделать что-либо после CollectionView
завершена перезагрузка:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
let newHeight : CGFloat = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height
var frame : CGRect! = self.myCollectionView.frame
frame.size.height = newHeight
self.myCollectionView.frame = frame
}
И не забудьте удалить наблюдателя:
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
....
....
self.myCollectionView.removeObserver(self, forKeyPath: "contentSize")
}
Я надеюсь, что это поможет вам быстро решить вашу проблему.
Ответ 8
Swift 4.2
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if bounds.size != intrinsicContentSize {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return self.contentSize
}
}
Ответ 9
Swift версия @user1046037:
public class DynamicCollectionView: UICollectionView {
override public func layoutSubviews() {
super.layoutSubviews()
if !bounds.size.equalTo(intrinsicContentSize) {
invalidateIntrinsicContentSize()
}
}
override public var intrinsicContentSize: CGSize {
let intrinsicContentSize: CGSize = contentSize
return intrinsicContentSize
}
}
Ответ 10
Кроме того: перед вызовом reloadData
лучше вызвать reloadData
: myCollectionView.collectionViewLayout.collectionViewContentSize
Ответ 11
Swift 4.2, Xcode 10.1, iOS 12.1:
По какой-то причине collectionView.contentSize.height
выглядел меньше разрешенной высоты моего представления коллекции. Во-первых, я использовал ограничение авторазметки относительно 1/2 высоты суперпредставления. Чтобы исправить это, я изменил ограничение на "безопасную область" представления.
Это позволило мне установить высоту ячейки для заполнения представления моей коллекции, используя collectionView.contentSize.height
:
private func setCellSize() {
let height: CGFloat = (collectionView.contentSize.height) / CGFloat(numberOfRows)
let width: CGFloat = view.frame.width - CGFloat(horizontalCellMargin * 2)
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
До
![bad simulator result]()
После
![good simulator result]()
Ответ 12
Этот ответ основан на @Er. Вихар ответь. Вы можете легко внедрить решение, используя RxSwift
collectionView.rx.observe(CGSize.self , "contentSize").subscribe(onNext: { (size) in
print("sizer \(size)")
}).disposed(by: rx.disposeBag)