Jak określić wysokość UICollectionView za pomocą FlowLayout

Mam UICollectionView z UICollectionViewFlowLayout i chcę obliczyć jego rozmiar zawartości (dla zwrotu w intrinsicContentSize potrzebnego do regulacji jego wysokości poprzez AutoLayout).

Problem polega na tym, że nawet jeśli mam stałą i równą wysokość dla wszystkich komórek, Nie wiem, ile "wierszy" / linii mam w UICollectionView. Nie mogę również określić, że liczy się przez liczbę pozycji w moim źródle danych, ponieważ komórki reprezentujące pozycje danych różnią się szerokością, więc w konsekwencji liczba pozycji mam w jednym wierszu UICollectionView.

Ponieważ nie mogłem znaleźć żadnych wskazówek na ten temat w oficjalnej dokumentacji, a googling nie przyniósł mi nic więcej, każda pomoc i pomysły będą bardzo mile widziane.

Author: Ignatius Tremor, 2012-12-09

8 answers

Whoa! Z jakiegoś powodu, po wielu godzinach badań, znalazłem dość łatwą odpowiedź na moje pytanie: szukałem całkowicie w niewłaściwym miejscu, przekopując się przez całą dokumentację, którą mogłem znaleźć na UICollectionView.

Proste i łatwe rozwiązanie leży w podstawowym układzie: po prostu wywołaj {[1] } na swojej właściwości myCollectionView.collectionViewLayout, a otrzymasz wysokość i szerokość zawartości jako CGSize. To takie proste.

 224
Author: Ignatius Tremor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-09 15:09:55

Jeśli używasz Auto layout , możesz utworzyć podklasę UICollectionView

Jeśli używasz poniższego kodu, nie musisz określać żadnych ograniczeń wysokości dla widoku kolekcji, ponieważ różni się ona w zależności od zawartości widoku kolekcji.

Poniżej podano implementację:

@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
 32
Author: user1046037,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-07 08:53:47

W viewDidAppear możesz go zdobyć przez:

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

Może po przeładowaniu danych trzeba obliczyć nową wysokość z nowymi danymi wtedy można ją uzyskać przez: dodaj observer do odsłuchu, gdy twoje CollectionView zakończyło reloadowanie danych w viewdidload:

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

Następnie dodaj funkcję poniżej, aby uzyskać nową wysokość lub zrób cokolwiek po zakończeniu przeładowania 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;    
}

I nie zapomnij usunąć obserwatora:

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];
 18
Author: lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-07 04:40:53

User1046037 odpowiedz W Swift...

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

    override func intrinsicContentSize() -> CGSize {
        return self.contentSize
    }
}
 9
Author: Nick Wood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-19 15:29:26

Swift 3 kod dla user1046037 odpowiedz

import UIKit

class DynamicCollectionView: UICollectionView {

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

    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

}
 7
Author: Mohammad Sadiq Shaikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-06 06:33:10

Jest już za późno, aby odpowiedzieć na to pytanie, ale ostatnio przejrzałem ten problem.
@lee ' s above answer help me a lot to get my answer. Ale ta odpowiedź jest ograniczona do objective-c i pracowałem w swift .
@lee w nawiązaniu do twojej odpowiedzi, pozwól mi pozwolić użytkownikowi swift łatwo rozwiązać ten problem. W tym celu wykonaj poniższe kroki:

Declare a CGFloat variable in declaration section:

var height : CGFloat!

At viewDidAppear można go dostać przez:

height = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height

Może Kiedy reload Dane będą musiały obliczyć nową wysokość z nowymi danymi, możesz je uzyskać przez: addObserver aby posłuchać, gdy twoje CollectionView skończy się przeładować dane na viewWillAppear:

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)
        ....
        ....
        self.shapeCollectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old, context: nil)
    }

Następnie dodaj funkcję poniżej, aby uzyskać nową wysokość lub zrób cokolwiek po collectionview zakończonym przeładowaniu:

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
    }

I nie zapomnij usunąć obserwatora:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(true)
    ....
    ....
    self.myCollectionView.removeObserver(self, forKeyPath: "contentSize")
}

Mam nadzieję, że to pomoże Ci rozwiązać twój problem w swift.

 2
Author: Er. Vihar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-06 13:21:34

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
  }
}
 2
Author: Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-23 03:01:15

Wersja 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
    }
}
 0
Author: Joshua Hart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-01 17:28:11