Как определить высоту UICollectionView с FlowLayout



у меня есть UICollectionView с UICollectionViewFlowLayout, и я хочу вычислить его размер содержимого (для возврата в intrinsicContentSize необходимый для регулировать свою высоту через AutoLayout).



проблемы: даже если у меня есть фиксированная и равная высота для всех ячеек, я не знаю, сколько "строк" / строк у меня есть в UICollectionView. Я также не могу определить это количество по количеству элементов в моем источнике данных, так как ячейки, представляющие элементы данных, различаются по ширине, поэтому количество элементов у меня есть в одной строке UICollectionView.



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

587   8  

8 ответов:

Эй! По какой-то причине, после нескольких часов исследований, я теперь нашел довольно простой ответ на свой вопрос: я полностью искал в неправильном месте, копаясь во всей документации, которую я мог найти на UICollectionView.

простое и легкое решение заключается в базовом макете: просто позвоните collectionViewContentSize на myCollectionView.collectionViewLayout свойство и вы получаете высоту и ширину содержимого как CGSize. Это так просто.

в случае, если вы используете автоматический макет, то вы можете создать подкласс 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

At viewDidAppear вы можете сделать это:

float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;

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

[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

затем добавьте функцию ниже, чтобы получить новую высоту или сделать что-нибудь после того, как collectionview закончил перезагрузку:

- (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;    
}

и не забудьте удалить observer:

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];

user1046037 ответ в Swift...

class DynamicCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize() {
            invalidateIntrinsicContentSize()
        }
    }

    override func intrinsicContentSize() -> CGSize {
        return self.contentSize
    }
}

Swift 3 Код для ответа user1046037

import UIKit

class DynamicCollectionView: UICollectionView {

    override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
        }

    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

}

слишком поздно отвечать на этот вопрос, но я недавно прошел через эту проблему.
@ли ответ выше поможет мне много, чтобы получить мой ответ. Но этот ответ ограничен С и работал в Свифт.
@lee со ссылкой на ваш ответ, позвольте мне позволить пользователю swift легко решить эту проблему. Для этого, пожалуйста, выполните следующие действия:

объявления CGFloat переменная в объявлении раздел:

var height : CGFloat!

At 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")
}

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

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
  }
}

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
    }
}

Comments

    Ничего не найдено.