UICollectionView in einer UITableViewCell - dynamische Höhe?

125

Für einen unserer Anwendungsbildschirme müssen wir ein UICollectionViewInneres in a platzieren UITableViewCell. Dies UICollectionViewhat eine dynamische Anzahl von Elementen, was zu einer Höhe führt, die ebenfalls dynamisch berechnet werden muss. Ich habe jedoch Probleme beim Versuch, die Höhe des Embedded zu berechnen UICollectionView.

Unsere übergreifende UIViewControllerwurde in Storyboards erstellt und verwendet das automatische Layout. Aber ich weiß nicht, wie ich die Höhe des UITableViewCellbasierend auf der Höhe des dynamisch erhöhen kann UICollectionView.

Kann jemand einige Tipps oder Ratschläge geben, wie dies erreicht werden kann?

Schattenmann
quelle
Können Sie etwas mehr über das Layout erzählen, das Sie erreichen möchten? Ist die Höhe der UITableViewCellsich von seiner acutal Tableview? UICollectionViewUITableView
Benötigen
3
Die Höhe der UITableViewCell soll dynamisch sein, basierend auf der Höhe der UICollectionView, die Teil der Tabellenansichtszelle ist. Das Layout meiner UICollectionView besteht aus 4 Spalten und einer dynamischen Anzahl von Zeilen. Bei 100 Elementen hätte ich also 4 Spalten und 25 Zeilen in meiner UICollectionView. Die Höhe der jeweiligen Zelle muss - wie in UITableViews heightForRowAtIndexPath angegeben - basierend auf der Größe dieser UICollectionView angepasst werden können. Ist das etwas klarer?
Shadowman
@ Shadowman, bitte schlagen Sie mir eine Lösung für diese Situation vor
Ravi Ojha

Antworten:

126

Die richtige Antwort ist JA , Sie KANN dies tun.

Ich bin vor einigen Wochen auf dieses Problem gestoßen. Es ist tatsächlich einfacher als Sie vielleicht denken. Legen Sie Ihre Zellen in NIBs (oder Storyboards) und stecken Sie sie fest, damit das automatische Layout die ganze Arbeit erledigt

Bei folgender Struktur:

Tabellenansicht

TableViewCell

CollectionView

CollectionViewCell

CollectionViewCell

CollectionViewCell

[... variable Anzahl von Zellen oder unterschiedliche Zellgrößen]

Die Lösung besteht darin, das automatische Layout anzuweisen, zuerst die Größe der collectionViewCell, dann die Größe der Sammlungsansicht contentSize zu berechnen und als Größe Ihrer Zelle zu verwenden. Dies ist die UIView- Methode, die "die Magie macht":

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

Sie müssen hier die Größe der TableViewCell festlegen, in Ihrem Fall die contentSize der CollectionView.

CollectionViewCell

In der CollectionViewCell müssen Sie die Zelle bei jedem Modellwechsel anweisen, ein Layout zu erstellen (z. B. wenn Sie ein UILabel mit einem Text festlegen, muss die Zelle erneut ein Layout aufweisen).

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

Die TableViewCell macht die Magie. Es verfügt über einen Auslass zu Ihrer Kollektion, ermöglicht das automatische Layout für Collection Zellen mit estimatedItemSize des UICollectionViewFlowLayout .

Der Trick besteht dann darin, die Größe Ihrer tableView-Zelle mit der systemLayoutSizeFittingSize ... -Methode festzulegen . (HINWEIS: iOS8 oder höher)

ANMERKUNG: Ich habe versucht, die Höhenmethode der delegierten Zelle in tableView zu -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPathverwenden. Es ist jedoch zu spät für das automatische Layoutsystem, die CollectionView contentSize zu berechnen, und manchmal finden Sie möglicherweise Zellen mit falscher Größenänderung.

@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

Denken Sie daran, das automatische Layoutsystem für die tableView-Zellen in Ihrem TableViewController zu aktivieren :

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

}

KREDIT: @rbarbera hat geholfen, das zu klären

Pablo Romeu
quelle
4
Ja. Das funktioniert. Dies sollte die akzeptierte Antwort sein.
Csotiriou
1
Kann mir irgendein Körper einen Beispielcode dafür geben? Ich möchte mehrere Bilder in der vertikalen Sammlungsansicht anzeigen, die sich innerhalb der Tabellenansichtszelle befindet.
Ravi Ojha
4
Schließlich hat dies für mich funktioniert, aber ich musste einen anderen Trick ausführen: cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);Dadurch wird eine lange Zelle mit einer langen CollectionView "simuliert", sodass die CollectionView die Größe aller ihrer Zellen berechnet. Andernfalls berechnete collectionView nur die sichtbaren Zellengrößen und stellte die Höhe der talbeViewCell falsch ein.
Ingaham
20
Wenn systemLayoutSizeFittingSizeich die Rahmenhöhe auf Maximum einstelle, stoße ich beim Neuladen der Zelle schnell auf ein Problem. Apps scheinen nach dem zu stecken self.collectionView.layoutIfNeeded(). Ich habe es behoben, indem ich die Rahmenhöhe auf 1 anstatt auf die maximale Höhe eingestellt habe. Hoffe, es hilft, wenn jemand über dieses Problem stolpert.
Titan
5
Hier ist, was es für mich behoben hat - in systemLayoutSizeFitting, kehren Sie die Reihenfolge um, was in der Antwort aktuell angezeigt wird, so dass zuerst collectionView.layoutIfNeeded()läuft, danncollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
xaphod
101

Ich denke, meine Lösung ist viel einfacher als die von @PabloRomeu vorgeschlagene.

Schritt 1. Erstellen Sie eine Steckdose von UICollectionViewbis UITableViewCell subclass, wo sie UICollectionViewplatziert ist. Lass es sein, der Name wird seincollectionView

Schritt 2. Fügen Sie IB für UICollectionViewHöhenbeschränkungen hinzu und erstellen Sie auch einen Auslass für UITableViewCell subclass. Lass es sein, der Name wird sein collectionViewHeight.

Schritt 3. tableView:cellForRowAtIndexPath:Fügen Sie Code hinzu:

// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;
Igor
quelle
1
Hast du das tatsächlich versucht? Es scheint nicht möglich zu sein, eine Höhenbeschränkung für die Sammlungsansicht festzulegen und sie an den Rändern der Tabellenansichtszelle anzuheften. Sie haben entweder zu wenige Einschränkungen (daher eine Warnung mit der Größe Null) oder widersprüchliche Einschränkungen (von denen eine ignoriert wird). Bitte erläutern Sie, wie Sie die Einschränkungen für diese Lösung festlegen.
Dale
2
Ich habe es geklappt. Ich füge Einschränkungen für collectionViewalle Seiten hinzu UITableViewCellund setze tableView.estimatedRowHeight = 44;undtableView.rowHeight = UITableViewAutomaticDimension;
Igor
3
Dieser funktioniert wie ein Champion ... einfach und effizient ... danke. Wenn es für jemanden nicht funktioniert, liegt der Grund wahrscheinlich darin, dass wir den unteren Rand der Sammlungsansicht an den unteren Rand der Tabellenansichtszelle binden müssen. Dann wird es anfangen zu arbeiten.
Viel Spaß
2
Würde dies funktionieren, wenn die Größe des Bildschirms geändert wird, beispielsweise durch Drehen eines iPad? Dies würde möglicherweise die Höhe der Auflistungsansicht und damit die Höhe der Zelle ändern. Wenn die Zelle jedoch auf dem Bildschirm angezeigt wird, muss sie möglicherweise nicht unbedingt von der Tabellenansicht neu geladen werden. Rufen Sie daher niemals die Methode cellForRowAtIndexPath: auf und geben Sie keine Chance dazu Ändern Sie die Einschränkungskonstante. Es kann jedoch möglich sein, reloadData zu erzwingen.
Carl Lindberg
2
Haben Sie verschiedene Größen von collectionView-Zellen ausprobiert? Das war mein problem Wenn Sie unterschiedliche Zellengrößen von collectionView haben, hat dies nicht funktioniert ... :(
Pablo Romeu
21

Sowohl Tabellenansichten als auch Sammlungsansichten sind UIScrollViewUnterklassen und möchten daher nicht in eine andere Bildlaufansicht eingebettet werden, da sie versuchen, Inhaltsgrößen zu berechnen, Zellen wiederzuverwenden usw.

Ich empfehle Ihnen, für alle Ihre Zwecke nur eine Sammlungsansicht zu verwenden.

Sie können es in Abschnitte unterteilen und das Layout einiger Abschnitte als Tabellenansicht und andere als Sammlungsansicht "behandeln". Schließlich können Sie mit einer Sammlungsansicht nichts erreichen, was Sie mit einer Tabellenansicht erreichen können.

Wenn Sie ein grundlegendes Rasterlayout für Ihre Sammlungsansicht "Teile" haben, können Sie auch reguläre Tabellenzellen verwenden, um diese zu verarbeiten. Wenn Sie jedoch keine iOS 5-Unterstützung benötigen, sollten Sie Sammlungsansichten besser verwenden.

Rivera
quelle
1
Sie haben "Treat" in Anführungszeichen gesetzt, weil Sie KEINE unterschiedlichen Layouts pro CollectionView-Abschnitt definieren können, oder? Ich habe keine Option gefunden, um unterschiedliche Layouts für verschiedene Abschnitte der Sammlungsansicht zu definieren. Übersehen ich etwas oder sprechen Sie davon, für verschiedene Abschnitte in meiner eigenen benutzerdefinierten Unterklasse von UICollectionViewLayout unterschiedlich auf 'layoutAttributesForItemAtIndexPath' zu reagieren?
Alex da Franca
Ja -> Sprechen Sie davon, layoutAttributesForItemAtIndexPathfür verschiedene Abschnitte in meiner eigenen benutzerdefinierten Unterklasse von unterschiedlich zu reagieren UICollectionViewLayout?
Rivera
2
@ Rivera, deine Antwort ist sehr vernünftig und klingt einfach richtig. Ich habe diesen Vorschlag an vielen Stellen gelesen. Könnten Sie auch einen Link zu Sample oder Tute teilen, wie dies erreicht werden kann, oder zumindest einige Hinweise? TIA
thesummersign
3
Bei Ihrer Antwort wird davon ausgegangen, dass Sie bei Null anfangen und noch keine große komplexe Tabellenansicht haben, in die Sie passen müssen. Die Frage wurde speziell zum Einfügen einer Sammlungsansicht in eine Tabellenansicht gestellt. IMO Ihre Antwort ist keine "Antwort"
Xaphod
2
Das ist eine schlechte Antwort. Sammlungsansichten in Tabellenansichten zu haben, ist so üblich, dass fast jede App dies tut.
Crashoverride777
9

Die Antwort von Pablo Romeu oben ( https://stackoverflow.com/a/33364092/2704206 ) hat mir bei meinem Problem sehr geholfen. Ich musste jedoch einige Dinge anders machen, damit dies für mein Problem funktioniert. Zunächst musste ich nicht layoutIfNeeded()so oft anrufen . Ich musste es nur collectionViewin der systemLayoutSizeFittingFunktion aufrufen .

Zweitens hatte ich automatische Layoutbeschränkungen für meine Sammlungsansicht in der Zelle der Tabellenansicht, um sie aufzufüllen. Also musste ich targetSize.widthbeim Einstellen der collectionView.frameBreite die vorderen und hinteren Ränder von den subtrahieren . Ich musste auch den oberen und unteren Rand zur Rückgabewerthöhe hinzufügen CGSize.

Um diese Einschränkungskonstanten zu erhalten, hatte ich die Möglichkeit, entweder Ausgänge für die Einschränkungen zu erstellen, ihre Konstanten fest zu codieren oder sie anhand eines Bezeichners nachzuschlagen. Ich habe mich für die dritte Option entschieden, um meine benutzerdefinierte Zellenklasse für die Tabellenansicht einfach wiederverwendbar zu machen. Am Ende war dies alles, was ich brauchte, um es zum Laufen zu bringen:

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

Als Hilfsfunktion zum Abrufen einer Einschränkung nach Bezeichner füge ich die folgende Erweiterung hinzu:

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

HINWEIS: Sie müssen den Bezeichner für diese Einschränkungen in Ihrem Storyboard oder überall dort festlegen, wo sie erstellt werden. Wenn sie keine 0-Konstante haben, spielt es keine Rolle. Wie in Pablos Antwort müssen Sie auch UICollectionViewFlowLayoutals Layout für Ihre Sammlungsansicht verwenden. collectionViewStellen Sie schließlich sicher, dass Sie das IBOutlet mit Ihrem Storyboard verknüpfen .

Mit der obigen benutzerdefinierten Tabellenansichtszelle kann ich sie jetzt in jede andere Tabellenansichtszelle unterordnen, die eine Sammlungsansicht benötigt, UICollectionViewDelegateFlowLayoutund die UICollectionViewDataSourceProtokolle und implementieren lassen . Hoffe das ist hilfreich für jemand anderen!

jmad8
quelle
5

Ich habe alle Antworten durchgelesen. Dies scheint allen Fällen zu dienen.

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
quelle
3

Eine Alternative zur Lösung von Pablo Romeu besteht darin, UICollectionView selbst anzupassen, anstatt die Arbeit in der Zelle der Tabellenansicht auszuführen.

Das zugrunde liegende Problem besteht darin, dass eine Sammlungsansicht standardmäßig keine intrinsische Größe hat und daher das automatische Layout nicht über die zu verwendenden Dimensionen informieren kann. Sie können dies beheben, indem Sie eine benutzerdefinierte Unterklasse erstellen, die eine nützliche Eigengröße zurückgibt.

Erstellen Sie eine Unterklasse von UICollectionView und überschreiben Sie die folgenden Methoden

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

(Sie sollten auch die zugehörigen Methoden überschreiben: reloadSections, reloadItemsAtIndexPaths auf ähnliche Weise wie reloadData ())

Durch Aufrufen von layoutIfNeeded wird die Sammlungsansicht gezwungen, die Inhaltsgröße neu zu berechnen, die dann als neue intrinsische Größe verwendet werden kann.

Außerdem müssen Sie Änderungen an der Ansichtsgröße (z. B. bei Gerätedrehung) im Tabellenansichts-Controller explizit behandeln

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }
}
Tal
quelle
Bro, könntest du bitte meinem Problem helfen ? stackoverflow.com/questions/44650058/… ?
Mai Phyu
3

Ich hatte kürzlich das gleiche Problem und habe fast jede Lösung in den Antworten ausprobiert. Einige davon haben funktioniert, andere waren nicht mein Hauptanliegen beim @ PabloRomeu- Ansatz. Wenn Sie andere Inhalte in der Zelle haben (außer der Sammlungsansicht), Sie müssen ihre Höhen und die Höhen ihrer Einschränkungen berechnen und das Ergebnis zurückgeben, um das richtige automatische Layout zu erhalten, und ich möchte die Dinge nicht manuell in meinem Code berechnen. Hier ist also die Lösung, die für mich ohne manuelle Berechnungen in meinem Code gut funktioniert hat.

In der cellForRow:atIndexPathTabellenansicht mache ich folgendes:

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
}

Ich denke, was hier passiert, ist, dass ich die Tabellenansichtszelle zwinge, ihre Höhe anzupassen, nachdem die Höhe der Sammlungsansicht berechnet wurde. (nach Angabe des CollectionView-Datums an die Datenquelle)

Abd Al-rhman Taher Badary
quelle
2

Ich würde der Sammlungsansichtsklasse eine statische Methode hinzufügen, die eine Größe basierend auf dem Inhalt zurückgibt, den sie haben wird. Verwenden Sie dann diese Methode in heightForRowAtIndexPath, um die richtige Größe zurückzugeben.

Beachten Sie auch, dass Sie beim Einbetten dieser Art von viewControllern ein seltsames Verhalten feststellen können. Ich habe es einmal gemacht und hatte einige seltsame Gedächtnisprobleme, die ich nie gelöst habe.

InkGolem
quelle
Für mich habe ich versucht, einen Tabellenansichts-Controller in Sammlungsansichts-Controller einzubetten. Jedes Mal, wenn eine Zelle wiederverwendet wird, wurden einige Einschränkungen für die automatische Wiedergabe gespeichert, die ich auf sie angewendet habe. Es war sehr fummelig und letztendlich eine schreckliche Idee. Ich denke, ich werde stattdessen nur eine einzelne Sammlungsansicht verwenden.
Fatuhoku
2

Vielleicht ist meine Variante nützlich; Ich habe diese Aufgabe in den letzten zwei Stunden entschieden. Ich gebe nicht vor, dass es 100% korrekt oder optimal ist, aber meine Fähigkeiten sind noch sehr klein und ich würde gerne Kommentare von Experten hören. Danke dir. Ein wichtiger Hinweis: Dies funktioniert für statische Tabellen - es wird von meiner aktuellen Arbeit angegeben. Ich verwende also nur viewWillLayoutSubviews von tableView . Und ein bisschen mehr.

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. Ich weiß, dass sich die collectionView in der ersten Zeile des zweiten Abschnitts befindet.
  2. Die Höhe der Reihe sei 17 p. größer als seine Inhaltshöhe;
  3. iconsCellHeight ist eine Zufallszahl, wenn das Programm startet (ich weiß, dass es im Hochformat genau 392 sein muss, aber es ist nicht wichtig). Wenn der Inhalt von collectionView + 17 dieser Zahl nicht entspricht, ändern Sie den Wert. Das nächste Mal in dieser Situation gibt die Bedingung FALSE;
  4. Immerhin aktualisieren Sie die tableView. In meinem Fall ist es die Kombination von zwei Operationen (zum netten Aktualisieren von erweiterten Zeilen);
  5. Und natürlich fügen Sie im heightForRowAtIndexPath eine Zeile zum Code hinzu.
Ilya A. Shuvaloff
quelle
2

Der einfachste Ansatz, den ich bisher gefunden habe: Credits to @igor Antwort oben,

Fügen Sie dies einfach in Ihre tableviewcell-Klasse ein

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

und natürlich ändern Sie das Collectionviewoutlet mit Ihrem Outlet in der Klasse der Zelle

Osa
quelle
1
Die Höhe der Zelle berechnet nicht richtig
Nik Kov
2

Ich bekomme eine Idee von @Igor post und investiere meine Zeit dafür schnell in mein Projekt

Einfach vorbei in deinem

 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
}

Ergänzung: Wenn Ihre UICollectionView beim Laden von Zellen abgehackt ist.

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
quelle
0

Pablos Lösung funktionierte für mich nicht sehr gut, ich hatte seltsame visuelle Effekte (die collectionView wurde nicht richtig angepasst).

Was funktionierte, war das Anpassen der Höhenbeschränkung der collectionView (als NSLayoutConstraint) an die collectionView contentSize während layoutSubviews(). Dies ist die Methode, die aufgerufen wird, wenn Autolayout auf die Zelle angewendet wird.

// 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
quelle
-3

In Ihrem UITableViewDelegate:

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

Ersetzen Sie itemCount und CollectionViewCellHeight durch die realen Werte. Wenn Sie ein Array von Arrays haben, könnte itemCount sein:

self.items[indexPath.row].count

Oder Wasauchimmer.

Martin
quelle
Ich denke, die Hauptfrage ist, wie man berechnet, collectionViewCellHeight bevor es rendert.
Thesummersign
-3

1.Erstellen Sie eine Dummy-Zelle.
2.Verwenden Sie die collectionViewContentSize-Methode in UICollectionViewLayout von UICollectionView unter Verwendung aktueller Daten.

Parag Shinde
quelle
Es sollte die beste Antwort sein ... da es keine Möglichkeit gibt, die Höhe der Zelle mit 'uicollectionview' festzulegen, ohne den Inhalt in die Dummy-Zelle zu legen, die Höhe abzurufen und ihn dann erneut auf die richtige Zelle
einzustellen
Wie verwende ich diese Methode?
Xtrinch
Fügen Sie ein Beispiel hinzu.
Nik Kov
-5

Sie können die Höhe der Sammlung berechnen auf der Grundlage ihrer Eigenschaften wie itemSize, sectionInset, minimumLineSpacing, minimumInteritemSpacing, wenn Ihr collectionViewCellden Rand einer Regel.

Sablib
quelle