UICollectionView wewnątrz UITableViewCell - dynamiczna wysokość?

125

Jeden z naszych ekranów aplikacji wymaga od nas umieszczenia UICollectionViewwewnątrz pliku UITableViewCell. To UICollectionViewbędzie mieć numer dynamicznych elementów, w wyniku wzrostu, które muszą być obliczane dynamicznie, jak również. Jednak napotykam problemy podczas próby obliczenia wysokości osadzenia UICollectionView.

Nasze nadrzędne UIViewControllerzostały stworzone w Storyboards i korzystają z automatycznego układu. Ale nie wiem, jak dynamicznie zwiększać wysokość na UITableViewCellpodstawie wysokości UICollectionView.

Czy ktoś może udzielić wskazówek lub porad, jak to osiągnąć?

Człowiek cień
źródło
czy możesz powiedzieć trochę więcej o układzie, który próbujesz osiągnąć? Czy wysokość elementu UITableViewCellróżni się od rzeczywistego widoku tabeli? Czy potrzebujesz przewijania w pionie zarówno na, jak UICollectionViewi naUITableView
apouche
3
Wysokość UITableViewCell powinna być dynamiczna na podstawie wysokości UICollectionView, która jest częścią komórki widoku tabeli. Układ mojego UICollectionView to 4 kolumny i dynamiczna liczba wierszy. Tak więc przy 100 elementach miałbym 4 kolumny i 25 wierszy w moim UICollectionView. Wysokość określonej komórki - jak wskazano w heightForRowAtIndexPath UITableView - musi być w stanie dostosować na podstawie rozmiaru tego UICollectionView. Czy to jest trochę bardziej jasne?
Shadowman,
@Shadowman, proszę zasugerować mi rozwiązanie tej sytuacji
Ravi Ojha

Odpowiedzi:

127

Prawidłowa odpowiedź brzmi TAK , MOŻESZ to zrobić.

Z tym problemem natknąłem się kilka tygodni temu. W rzeczywistości jest to łatwiejsze niż myślisz. Umieść swoje komórki w NIB (lub scenorysach) i przypnij je, aby automatyczny układ wykonał całą pracę

Biorąc pod uwagę następującą strukturę:

TableView

TableViewCell

CollectionView

CollectionViewCell

CollectionViewCell

CollectionViewCell

[... zmienna liczba komórek lub różne rozmiary komórek]

Rozwiązaniem jest poinformowanie układu automatycznego, aby najpierw obliczył rozmiary collectionViewCell, a następnie contentSize widoku kolekcji i użyć go jako rozmiaru komórki. Oto metoda UIView , która „robi magię”:

-(void)systemLayoutSizeFittingSize:(CGSize)targetSize 
     withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority 
           verticalFittingPriority:(UILayoutPriority)verticalFittingPriority

Musisz ustawić tutaj rozmiar TableViewCell, który w twoim przypadku jest ContentSize CollectionView.

CollectionViewCell

W CollectionViewCell musisz powiedzieć komórce, aby układała się za każdym razem, gdy zmieniasz model (np .: ustawiasz UILabel z tekstem, a następnie komórka musi być ponownie ułożona).

- (void)bindWithModel:(id)model {
    // Do whatever you may need to bind with your data and 
    // tell the collection view cell's contentView to resize
    [self.contentView setNeedsLayout];
}
// Other stuff here...

TableViewCell

TableViewCell czyni magię. To ma wylot do swojego CollectionView umożliwia układ automatycznego dla komórek CollectionView korzystających estimatedItemSize z UICollectionViewFlowLayout .

Następnie sztuczka polega na ustawieniu rozmiaru komórki tableView w metodzie systemLayoutSizeFittingSize ... (UWAGA: iOS8 lub nowszy)

UWAGA: Próbowałem użyć metody wysokości komórki delegata w tableView., -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPathAle jest już za późno, aby system automatycznego układu obliczył CollectionView contentSize i czasami możesz znaleźć niewłaściwe komórki o zmienionym rozmiarze.

@implementation TableCell

- (void)awakeFromNib {
    [super awakeFromNib];
    UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;

    // Configure the collectionView
    flow.minimumInteritemSpacing = ...;

    // This enables the magic of auto layout. 
    // Setting estimatedItemSize different to CGSizeZero 
    // on flow Layout enables auto layout for collectionView cells.
    // https://developer.apple.com/videos/play/wwdc2014-226/
    flow.estimatedItemSize = CGSizeMake(1, 1);

    // Disable the scroll on your collection view
    // to avoid running into multiple scroll issues.
    [self.collectionView setScrollEnabled:NO];
}

- (void)bindWithModel:(id)model {
    // Do your stuff here to configure the tableViewCell
    // Tell the cell to redraw its contentView        
    [self.contentView layoutIfNeeded];
}

// THIS IS THE MOST IMPORTANT METHOD
//
// This method tells the auto layout
// You cannot calculate the collectionView content size in any other place, 
// because you run into race condition issues.
// NOTE: Works for iOS 8 or later
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {

    // With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width)
    self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT);
    [self.collectionView layoutIfNeeded];

    // If the cell's size has to be exactly the content 
    // Size of the collection View, just return the
    // collectionViewLayout's collectionViewContentSize.

    return [self.collectionView.collectionViewLayout collectionViewContentSize];
}

// Other stuff here...

@end

TableViewController

Pamiętaj, aby włączyć system automatycznego układu dla komórek tableView w swoim TableViewController :

- (void)viewDidLoad {
    [super viewDidLoad];

    // Enable automatic row auto layout calculations        
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    // Set the estimatedRowHeight to a non-0 value to enable auto layout.
    self.tableView.estimatedRowHeight = 10;

}

KREDYT : @rbarbera pomógł rozwiązać ten problem

Pablo Romeu
źródło
4
Tak. To działa. To powinna być akceptowana odpowiedź.
csotiriou
1
Czy jakikolwiek organ może dostarczyć mi przykładowy kod? chcę pokazać wiele obrazów w pionowym widoku kolekcji, który znajduje się w komórce widoku tabeli ..
Ravi Ojha
4
W końcu to zadziałało, ale musiałem zrobić inną sztuczkę: cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);to „zasymuluje” długą komórkę z długim collectionView, więc collectionView obliczy rozmiar wszystkich swoich komórek. W przeciwnym razie collectionView oblicza tylko widoczne rozmiary komórek i ustawia nieprawidłowo wysokość talbeViewCell.
ingaham
20
po ustawieniu wysokości ramki na maksimum w systemLayoutSizeFittingSize, szybko napotkałem problem podczas ponownego ładowania komórki, aplikacje wydają się blokować po self.collectionView.layoutIfNeeded(). Naprawiłem to, ustawiając wysokość ramy na 1 zamiast maksymalnej wysokości. Mam nadzieję, że to pomoże, jeśli ktoś natknie się na ten problem.
titan
6
Oto, co naprawiło to dla mnie - w systemLayoutSizeFitting, odwróć kolejność tego, co jest obecnie pokazane w odpowiedzi, więc najpierw collectionView.layoutIfNeeded()działa, a następniecollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
xaphod
101

Myślę, że moje rozwiązanie jest znacznie prostsze niż to zaproponowane przez @PabloRomeu.

Krok 1. Utwórz gniazdko od UICollectionViewdo UITableViewCell subclass, w którym się UICollectionViewznajduje. Niech to będzie imięcollectionView

Krok 2. Dodaj IB dla UICollectionViewograniczenia wysokości i utwórz również wylot UITableViewCell subclass. Niech to będzie imię collectionViewHeight.

Krok 3. W tableView:cellForRowAtIndexPath:dodaniu kodu:

// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;
Igor
źródło
1
Czy faktycznie próbowałeś tego? Wydaje się, że nie można jednocześnie ustawić ograniczenia wysokości w widoku kolekcji i przypiąć go do marginesów komórki widoku tabeli. Albo skończysz ze zbyt małą liczbą ograniczeń (stąd ostrzeżenie o zerowym rozmiarze), albo skończysz ze sprzecznymi ograniczeniami (z których jedno jest ignorowane). Proszę wyjaśnić, jak ustawić ograniczenia dla tego rozwiązania.
Dale,
2
Mam to zadziałało. Dodam ograniczeniami dla collectionViewwszystkich stron UITableViewCelli ustawić tableView.estimatedRowHeight = 44;itableView.rowHeight = UITableViewAutomaticDimension;
Igor
3
Ten działa jak mistrz ... prosty i skuteczny ... dziękuję. Jeśli dla kogoś to nie działa, prawdopodobnie przyczyną może być powiązanie dolnej części widoku kolekcji z dolną częścią komórki widoku tabeli. Wtedy zacznie działać. Miłego kodowania .. :)
Sebin Roy
2
Czy to zadziała, gdy rozmiar ekranu zostanie zmieniony, na przykład obracając iPada? Mogłoby to potencjalnie zmienić wysokość widoku kolekcji, a tym samym wysokość komórki, ale jeśli na ekranie komórka niekoniecznie musi zostać ponownie załadowana przez widok tabeli, nigdy nie wywołuje metody cellForRowAtIndexPath: i nie daje szansy na zmienić stałą wiązania. Możliwe jest jednak wymuszenie reloadData.
Carl Lindberg
2
Czy próbowałeś różnych rozmiarów komórek CollectionView? To był mój problem. Jeśli masz różne rozmiary komórek CollectionView, to nie zadziałało ... :(
Pablo Romeu
22

Zarówno widoki tabeli, jak i widoki kolekcji są UIScrollViewpodklasami i dlatego nie lubią być osadzane w innym widoku przewijania, gdy próbują obliczyć rozmiary zawartości, ponownie wykorzystać komórki itp.

Zalecam używanie tylko widoku kolekcji do wszystkich celów.

Możesz podzielić go na sekcje i „traktować” układ niektórych sekcji jako widok tabeli, a innych jako widok zbioru. W końcu nie ma nic, czego nie można osiągnąć w widoku kolekcji, czego można by uzyskać w widoku tabeli.

Jeśli masz podstawowy układ siatki dla „części” widoku kolekcji, możesz również użyć zwykłych komórek tabeli do ich obsługi. Jeśli jednak nie potrzebujesz obsługi iOS 5, lepiej korzystaj z widoków kolekcji.

Rivera
źródło
1
Umieściłeś słowo „traktuj” w cudzysłowie, ponieważ NIE możesz zdefiniować różnych układów dla sekcji CollectionView, prawda? Nie znalazłem opcji definiowania różnych układów dla różnych sekcji widoku kolekcji. Czy coś przeoczę, czy też mówisz o odmiennej odpowiedzi na „layoutAttributesForItemAtIndexPath” dla różnych sekcji w mojej własnej niestandardowej podklasie UICollectionViewLayout?
alex da franca
Tak -> Czy mówisz o różnym reagowaniu layoutAttributesForItemAtIndexPathna różne sekcje w mojej własnej podklasie UICollectionViewLayout?
Rivera
2
@ Rivera, twoja odpowiedź jest jak najbardziej rozsądna i brzmi po prostu poprawnie. Czytałem tę sugestię w wielu miejscach. Czy mógłbyś również udostępnić jakiś link do próbki lub tutoriale, jak to osiągnąć lub przynajmniej kilka wskazówek. TIA
thesummersign
3
Twoja odpowiedź zakłada, że ​​zaczynasz od zera i nie masz jeszcze dużego złożonego widoku tabeli, do którego musisz się dopasować. Pytanie konkretnie zadawane o umieszczanie widoku kolekcji w widoku tabeli. IMO Twoja odpowiedź nie jest „odpowiedzią”
xaphod,
2
To zła odpowiedź. Posiadanie widoków kolekcji w widokach tabel jest tak powszechną czynnością, że prawie każda aplikacja to robi.
crashoverride777
10

Powyższa odpowiedź Pablo Romeu ( https://stackoverflow.com/a/33364092/2704206 ) bardzo mi pomogła w rozwiązaniu mojego problemu. Musiałem jednak zrobić kilka rzeczy inaczej, aby to zadziałało. Po pierwsze, nie musiałem dzwonić layoutIfNeeded()tak często. Musiałem tylko wywołać to collectionVieww systemLayoutSizeFittingfunkcji.

Po drugie, miałem ograniczenia automatycznego układu w moim widoku kolekcji w komórce widoku tabeli, aby nadać mu pewne wypełnienie. Musiałem więc odjąć wiodący i końcowy margines odtargetSize.width podczas ustawiania collectionView.frameszerokości. Musiałem również dodać górny i dolny margines do CGSizewysokości zwracanej wartości .

Aby uzyskać te stałe ograniczenia, miałem możliwość albo utworzenia wyjść dla ograniczeń, zakodowania ich stałych na stałe, albo wyszukania ich za pomocą identyfikatora. Zdecydowałem się na trzecią opcję, aby moja niestandardowa klasa komórek widoku tabeli była łatwa do ponownego wykorzystania. W końcu to było wszystko, czego potrzebowałem, aby to działało:

class CollectionTableViewCell: UITableViewCell {

    // MARK: -
    // MARK: Properties
    @IBOutlet weak var collectionView: UICollectionView! {
        didSet {
            collectionViewLayout?.estimatedItemSize = CGSize(width: 1, height: 1)
            selectionStyle = .none
        }
    }

    var collectionViewLayout: UICollectionViewFlowLayout? {
        return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    }

    // MARK: -
    // MARK: UIView functions
    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()

        let topConstraintConstant = contentView.constraint(byIdentifier: "topAnchor")?.constant ?? 0
        let bottomConstraintConstant = contentView.constraint(byIdentifier: "bottomAnchor")?.constant ?? 0
        let trailingConstraintConstant = contentView.constraint(byIdentifier: "trailingAnchor")?.constant ?? 0
        let leadingConstraintConstant = contentView.constraint(byIdentifier: "leadingAnchor")?.constant ?? 0

        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width - trailingConstraintConstant - leadingConstraintConstant, height: 1)

        let size = collectionView.collectionViewLayout.collectionViewContentSize
        let newSize = CGSize(width: size.width, height: size.height + topConstraintConstant + bottomConstraintConstant)
        return newSize
    }
}

Jako funkcję pomocniczą do pobierania ograniczenia według identyfikatora dodaję następujące rozszerzenie:

extension UIView {
    func constraint(byIdentifier identifier: String) -> NSLayoutConstraint? {
        return constraints.first(where: { $0.identifier == identifier })
    }
}

UWAGA: Będziesz musiał ustawić identyfikator tych ograniczeń w swoim storyboardzie lub gdziekolwiek są tworzone. Jeśli nie mają stałej 0, to nie ma to znaczenia. Ponadto, podobnie jak w odpowiedzi Pablo, będziesz musiał użyćUICollectionViewFlowLayout jako układu widoku kolekcji. Na koniec upewnij się, że łączysz collectionViewIBOutlet ze swoim scenorysem.

Dzięki powyższej komórce niestandardowego widoku tabeli mogę teraz podklasować ją w dowolnej innej komórce widoku tabeli, która wymaga widoku kolekcji, i zaimplementować protokoły UICollectionViewDelegateFlowLayouti UICollectionViewDataSource. Mam nadzieję, że to pomoże komuś innemu!

jmad8
źródło
5

Przeczytałem wszystkie odpowiedzi. Wydaje się, że to służy wszystkim.

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()
        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width , height: 1)
        return collectionView.collectionViewLayout.collectionViewContentSize
}
SRP-Achiever
źródło
3

Alternatywą dla rozwiązania Pablo Romeu jest dostosowanie samego UICollectionView zamiast wykonywania pracy w komórce widoku tabeli.

Podstawowy problem polega na tym, że domyślnie widok kolekcji nie ma wewnętrznego rozmiaru i dlatego nie może informować automatycznego układu o wymiarach, które mają być używane. Możesz temu zaradzić, tworząc niestandardową podklasę, która zwraca użyteczny rozmiar wewnętrzny.

Utwórz podklasę UICollectionView i Zastąp następujące metody

override func intrinsicContentSize() -> CGSize {
    self.layoutIfNeeded()

    var size = super.contentSize
    if size.width == 0 || size.height == 0 {
        // return a default size
        size = CGSize(width: 600, height:44)
    }

    return size
 }

override func reloadData() {
    super.reloadData()
    self.layoutIfNeeded()
    self.invalidateIntrinsicContentSize()
}

(Powinieneś także nadpisać powiązane metody: reloadSections, reloadItemsAtIndexPaths w podobny sposób jak reloadData ())

Wywołanie layoutIfNeeded wymusza na widoku kolekcji ponowne obliczenie rozmiaru zawartości, który może następnie zostać użyty jako nowy rozmiar wewnętrzny.

Ponadto musisz jawnie obsłużyć zmiany rozmiaru widoku (np. Przy obracaniu urządzenia) w kontrolerze widoku tabeli

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }
}
Dołek
źródło
stary, czy mógłbyś pomóc w moim problemie stackoverflow.com/questions/44650058/… ?
Maj Phyu
3

Ostatnio miałem do czynienia z tym samym problemem i prawie próbowałem każdego rozwiązania w odpowiedziach, niektóre z nich działały, a inne nie były moim głównym zmartwieniem podejściu @PabloRomeu jest to, że jeśli masz inną zawartość w komórce (poza widokiem kolekcji) będziesz musiał obliczyć ich wysokości i wysokości ich ograniczeń i zwrócić wynik, aby uzyskać prawidłowy układ automatyczny, a ja nie lubię obliczać rzeczy ręcznie w moim kodzie. Oto rozwiązanie, które działało dobrze bez wykonywania żadnych ręcznych obliczeń w moim kodzie.

w cellForRow:atIndexPathwidoku tabeli wykonuję następujące czynności:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    //initialize the the collection view data source with the data
    cell.frame = CGRect.zero
    cell.layoutIfNeeded()
    return cell
}

Myślę, że to, co się tutaj dzieje, polega na tym, że zmuszam komórkę widoku tabeli do dostosowania jej wysokości po obliczeniu wysokości widoku kolekcji. (po podaniu daty collectionView do źródła danych)

Abd al-rhman Taher Badary
źródło
2

Umieściłbym statyczną metodę w klasie widoku kolekcji, która zwróci rozmiar na podstawie zawartości, którą będzie miała. Następnie użyj tej metody w, heightForRowAtIndexPathaby zwrócić właściwy rozmiar.

Zauważ również, że osadzając tego rodzaju kontrolery widoku, możesz uzyskać dziwne zachowanie. Zrobiłem to raz i miałem dziwne problemy z pamięcią, których nigdy nie rozwiązałem.

InkGolem
źródło
W moim przypadku próbowałem osadzić kontroler widoku tabeli w kontrolerach widoku kolekcji. Za każdym razem, gdy komórka jest ponownie używana, kończyło się na zapamiętywaniu pewnych ograniczeń autoukładu, które na nie zastosowałem. Był to bardzo skomplikowany pomysł i ostatecznie był to okropny pomysł. Myślę, że zamiast tego użyję tylko jednego widoku kolekcji.
fatuhoku
2

Może mój wariant się przyda; decydowałem się na to zadanie w ciągu ostatnich dwóch godzin. Nie udaję, że jest to w 100% poprawne lub optymalne, ale moje umiejętności są jeszcze bardzo małe i chciałbym usłyszeć komentarze ekspertów. Dziękuję Ci. Jedna ważna uwaga: działa to dla tabeli statycznej - jest to określone w mojej bieżącej pracy. Więc wszystko, czego używam, to viewWillLayoutSubviews of tableView . I trochę więcej.

private var iconsCellHeight: CGFloat = 500 

func updateTable(table: UITableView, withDuration duration: NSTimeInterval) {
    UIView.animateWithDuration(duration, animations: { () -> Void in
        table.beginUpdates()
        table.endUpdates()
    })
}

override func viewWillLayoutSubviews() {
    if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell {
        let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height
        if collectionViewContentHeight + 17 != iconsCellHeight {
            iconsCellHeight = collectionViewContentHeight + 17
            updateTable(tableView, withDuration: 0.2)
        }
    }
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    switch (indexPath.section, indexPath.row) {
        case ...
        case (1,0):
            return iconsCellHeight
        default:
            return tableView.rowHeight
    }
}
  1. Wiem, że collectionView znajduje się w pierwszym wierszu drugiej sekcji;
  2. Niech wysokość rzędu wynosi 17 p. większa niż wysokość zawartości;
  3. iconsCellHeight to liczba losowa w momencie startu programu (wiem, że w formie portretu musi to być dokładnie 392, ale to nie jest ważne). Jeśli zawartość collectionView + 17 nie jest równa tej liczbie, zmień jej wartość. Następnym razem w tej sytuacji warunek daje FALSE;
  4. Po tym wszystkim zaktualizuj tableView. W moim przypadku jest to połączenie dwóch operacji (dla ładnej aktualizacji rozszerzających się wierszy);
  5. I oczywiście w heightForRowAtIndexPath dodaj jeden wiersz do kodu.
Ilya A. Shuvaloff
źródło
2

Najłatwiejsze podejście, jakie do tej pory wymyśliłem, Kredyty na odpowiedź @igor powyżej,

W swojej klasie tableviewcell po prostu wstaw to

override func layoutSubviews() {
    self.collectionViewOutlet.constant = self.postPoll.collectionViewLayout.collectionViewContentSize.height
}

i oczywiście zmień punkt odbioru kolekcji na wylot w klasie celi

Osa
źródło
1
Wysokość komórki nie jest obliczana poprawnie
Nik Kov
2

Mam pomysł od @Igor post i inwestuję w to swój czas

Po prostu minęło to w twoim

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    cell.frame = tableView.bounds
    cell.layoutIfNeeded()
    cell.collectionView.reloadData()
    cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height)
    cell.layoutIfNeeded()
    return cell
}

Dodawanie: Jeśli widzisz, że UICollectionView zacina się podczas ładowania komórek.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {       
  //do dequeue stuff
  cell.layer.shouldRasterize = true
  cell.layer.rasterizationScale = UIScreen.main.scale
  return cell
}
Nazmul Hasan
źródło
0

Rozwiązanie Pablo nie działało zbyt dobrze dla mnie, miałem dziwne efekty wizualne (widok kolekcji nie dostosowywał się poprawnie).

To, co działało, polegało na dostosowaniu ograniczenia wysokości collectionView (jako NSLayoutConstraint) do contentSize collectionView podczas layoutSubviews(). Jest to metoda wywoływana w przypadku zastosowania automatycznego układu do komórki.

// Constraint on the collectionView height in the storyboard. Priority set to 999.
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!


// Method called by autolayout to layout the subviews (including the collectionView).
// This is triggered with 'layoutIfNeeded()', or by the viewController
// (happens between 'viewWillLayoutSubviews()' and 'viewDidLayoutSubviews()'.
override func layoutSubviews() {

    collectionViewHeightConstraint.constant = collectionView.contentSize.height
    super.layoutSubviews()
}

// Call `layoutIfNeeded()` when you update your UI from the model to trigger 'layoutSubviews()'
private func updateUI() {
    layoutIfNeeded()
}
Frédéric Adda
źródło
-3

W Twoim UITableViewDelegate:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return ceil(itemCount/4.0f)*collectionViewCellHeight;
}

Zastąp itemCount i CollectionViewCellHeight wartościami rzeczywistymi. Jeśli masz tablicę tablic itemCount może wynosić:

self.items[indexPath.row].count

Lub cokolwiek.

Jaskółka oknówka
źródło
Myślę, że głównym pytaniem jest, jak obliczyć collectionViewCellHeight przed renderowaniem.
thesummersign
-3

1. Stwórz atrapę komórki.
2. Użyj metody collectionViewContentSize na UICollectionViewLayout z UICollectionView przy użyciu bieżących danych.

Parag Shinde
źródło
Powinna być jak najlepsza odpowiedź ... ponieważ nie ma możliwości ustawienia wysokości komórki za pomocą 'uicollectionview' bez wstawienia zawartości do atrapy komórki, uzyskania wysokości, a następnie ponownego ustawienia jej na właściwą komórkę
Bartłomiej Semańczyk
jak używać tej metody?
xtrinch
Dodaj przykład.
Nik Kov
-5

Można obliczyć wysokość zbiorów na podstawie jego właściwości, takich jak itemSize, sectionInset, minimumLineSpacing, minimumInteritemSpacing, jeśli collectionViewCellma granicę reguły.

sablib
źródło