Wie kann ich die Höhe von UICollectionView an die Höhe der Inhaltsgröße von UICollectionView anpassen?

74

Ich möchte, dass die UICollectionView (die rote) auf die Höhe der Inhaltsgröße verkleinert wird, in diesem Fall die UICollectionViewCells (die gelben), da viel Leerraum vorhanden ist. Was ich versucht habe, ist zu verwenden:

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

override var intrinsicContentSize: CGSize {
    return self.collection.contentSize
}

aber return self.collection.contentSizeimmer zurückgeben (Breite, 0) und aus diesem Grund schrumpft es zu stark auf den Wert von Höhe 30 (Der Wert, den ich in der XIB-Datei für die Höhe festgelegt habe, obwohl ich Konstante> = 30 habe).

Geben Sie hier die Bildbeschreibung ein

charbinary
quelle
1
Sie müssen die Höhenbeschränkung von ColletionView nehmen und die Höhe wie folgt anpassenheightConstraint.constant = collectionView.contentSize.height
dahiya_boy
Verwenden Sie ein benutzerdefiniertes Layout oder das von Apple bereitgestellte UICollectionViewFlowLayout?
Georgi Boyadzhiev
Ich verwende die Standardeinstellung UICollectionViewFlowLayout
charbinary
Dann sollten Sie collectionViewLayout.collectionViewContentSize verwenden, siehe die Antwort von @ hasan83. Es ist eine Möglichkeit für Sie.
Georgi Boyadzhiev

Antworten:

168

Ich würde folgendes vorschlagen:

  1. Fügen Sie Ihrer Sammlungsansicht eine Höhenbeschränkung hinzu.
  2. Stellen Sie die Priorität auf 999 ein.
  3. Stellen Sie die Konstante auf einen Wert ein, der sie im Storyboard angemessen sichtbar macht.
  4. Ändern Sie die untere Gleichheitsbedingung der Sammlungsansicht in "Größer" oder "Gleich".
  5. Schließen Sie die Höhenbeschränkung an eine Steckdose an.
  6. Gehen Sie bei jedem erneuten Laden der Daten in der Sammlungsansicht wie folgt vor:

Möglicherweise möchten Sie auch den Einschub der Sammlungsansicht berücksichtigen, indem Sie ihn zur Inhaltsgröße hinzufügen.

Codebeispiel:

CGFloat height = myCollectionView.collectionViewLayout.collectionViewContentSize.height
heightConstraint.constant = height
self.view.setNeedsLayout() Or self.view.layoutIfNeeded()

Erläuterung: Extra, Sie müssen nicht lesen, wenn Sie es verstehen. offensichtlich!!

Die Benutzeroberfläche wird versuchen, alle Einschränkungen widerzuspiegeln, unabhängig von ihren Prioritäten. Da die Höhenbeschränkung eine niedrigere Priorität von (999) und eine untere Einschränkung vom Typ größer oder gleich hat. Wenn die Höhenbeschränkungskonstante auf einen Wert festgelegt wird, der kleiner als die Höhe der übergeordneten Ansicht ist, entspricht die Sammlungsansicht der angegebenen Höhe, wodurch beide Einschränkungen erreicht werden.

Wenn die Höhenbeschränkungskonstante jedoch auf einen Wert festgelegt wird, der über der Höhe der übergeordneten Ansicht liegt, können beide Einschränkungen nicht erreicht werden. Daher wird nur die Einschränkung mit der höheren Priorität erreicht, die die größere oder gleiche untere Einschränkung ist.

Das Folgende ist nur eine Vermutung aus einer Erfahrung. So erreicht es eine Konstrante. Es wird jedoch auch versucht, den Fehler in der resultierenden Benutzeroberfläche für die andere nicht erreichte Einschränkung mit niedrigerer Priorität so niedrig wie möglich zu halten . Daher entspricht die Höhe der Sammlungsansicht der Größe der übergeordneten Ansicht.

hasan
quelle
Meins dehnt sich bis zu einem gewissen Grad aus, ist aber nicht perfekt. Es fehlen ca. 3 4 Zeilen des Etiketts. Irgendeine Idee? So sieht es aus: ibb.co/jeO9Rv ibb.co/iV8b6v
nr5
@Nil Haben Sie eine Kopf- oder Fußzeile in Ihrer Sammlungsansicht? Die Höhe der Fußzeile und der Kopfzeile muss hinzugefügt werden.
Hasan
Egal, es hat funktioniert. Die Höhenbeschränkung wurde auf proportionale Höhe eingestellt, weshalb das Festlegen nur der Konstanten einen großen Unterschied machte.
Nr. 5
Haben Sie während des Gesprächs eine Idee, wie Sie eine Zelle oben anheften können? In meiner horizontalen Sammlungsansicht sind einige Zellen nicht oben angeheftet. Nur zufällig in der Mitte schweben. Hier: ibb.co/fHbSwv
Nr. 5
@ hasan83 Auf diese Weise erhalte ich eine zusätzliche Höhe der Sammlungsansicht. Irgendwelche Vorschläge?
Mitesh Dobareeya
17

1) Stellen Sie die feste Höhe Ihrer CollectionView ein.

2) Erstellen Sie einen Ausgang dieser CollectionView-Höhenkonstante. Mögen :

IBOutlet NSLayoutConstraint * constHeight;

3) Fügen Sie die folgende Methode in Ihre .m-Datei ein:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGFloat height = collectionMenu.collectionViewLayout.collectionViewContentSize.height;
    constHeight.constant = height;
}
Parth Patel
quelle
3
Dies funktionierte mit Swift 5und Xcode 10.2.1. Vielen Dank.
Pankaj Kulkarni
15

Am Ende habe ich die UICollectionViewfolgenden Methoden in Unterklassen unterteilt und einige Methoden überschrieben.

  • Wenn Sie self.collectionViewLayout.collectionViewContentSizefür zurückkehren, stellen Sie intrinsicContentSizesicher, dass Sie immer die richtige Größe haben
  • Rufen Sie es dann einfach an, wann immer es sich ändern könnte (wie am reloadData)

Code:

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

override var intrinsicContentSize: CGSize {
    return self.collectionViewLayout.collectionViewContentSize
}

Beachten Sie jedoch, dass Sie die "Wiederverwendung von Zellen" verlieren, wenn Sie große Datenmengen anzeigen, obwohl diese nicht auf den Bildschirm passen.

d4Rk
quelle
Dies funktioniert, um die UICollectionViewanfängliche Größe des Inhalts festzulegen. Wenn sich der Inhalt jedoch ändert, z. B.: Zeilen einfügen oder löschen, wird die Größe nicht geändert. Und wenn ich Daten neu laden aufrufe, ruckelt die Sammlungsansicht beim Ändern der Größe. Wie kann man dieses Stottern stoppen?
Cabyambo
Haben Sie versucht anzurufen, self.invalidateIntrinsicContentSize()ohne anzurufen reloadData()? Vielleicht könnte das funktionieren.
d4Rk
1
Mit Abstand die schönste Lösung - zumindest für meinen Anwendungsfall. Vielen Dank. Es löst das Problem des Timings. Für das Layout müssen alle anderen Einschränkungen und Ansichten angepasst werden, um die Größe des Inhalts zu bestimmen. Diese Funktion funktioniert einfach.
n13
1
Eigentlich - ich musste die intrinsische Größe auf mindestens 1 - niemals 0 - beschränken, damit dies richtig funktioniert. Ansonsten gab es kleine Fehler bei der Berechnung, die den unteren Rand der Ansicht um einige Pixel abschnitten.
n13
1
@AnthonyMDev Da Sie diesen Ansatz verwenden, ändern Sie die Größe der Sammlungsansicht so, dass alle Elemente gleichzeitig angezeigt werden, sodass alle Elemente jederzeit geladen werden.
d4Rk
10

Sie müssen die Höhenbeschränkung gleich der Inhaltsgröße festlegen

HeightConstraint.constant = collection.contentSize.height 
Bhanupriya
quelle
9

In Swift 5 und Xcode 10.2.1

  1. Höhe der CollectionView korrigieren

  2. Erstellen Sie ein Outlet Ihrer CollectionViewHeight

    IBOutlet weak var myCollectionViewHeight: NSLayoutConstraint!
    
  3. Verwenden Sie den folgenden Code

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let height = myCollectionView.collectionViewLayout.collectionViewContentSize.height
        myCollectionViewHeight.constant = height
        self.view.layoutIfNeeded()
    }
    
iOS
quelle
Was macht es myCollectionView in Ihrem Code. Wo Sie deklariert haben
Karthi Rasu
@ Karthi Rasu, myCollectionView ist Ihre Höhenbeschränkung für die Sammlungsansicht. Wenn Sie das Storyboard verwenden, korrigieren Sie die Höhe von collectionView.
iOS
1
Perfekte Lösung !!
Vinayak Bhor
4

Dies schien mir die einfachste Lösung zu sein.

class SelfSizingCollectionView: UICollectionView {
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit() {
        isScrollEnabled = false
    }

    override var contentSize: CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

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

    override var intrinsicContentSize: CGSize {
        return contentSize
    }
}

Möglicherweise müssen Sie nicht überschreiben reloadData

Tyten
quelle
1
Dies war das einzige, was unter iOS 14 für mich funktioniert hat. Danke!
Teddy K
3

Folgen Sie den Anweisungen.

  1. Stellen Sie zuerst die Höhenbeschränkung für ein UICollectionView
  2. Hier calendarBaseViewHeightist die UICollectionViewHöhe variabel
  3. Rufen Sie die Funktion auf, nachdem Sie die Sammlungsansicht neu geladen haben

    func resizeCollectionViewSize(){  
           calendarBaseViewHeight.constant = collectionView.contentSize.height      
     }
    
parthiban
quelle
3

Ich habe die Lösung von d4Rk übernommen, was großartig ist, außer in meinem Fall würde sie den unteren Rand meiner Sammlungsansicht immer wieder abschneiden (zu kurz). Ich fand heraus, dass dies daran lag, dass die intrinsische Inhaltsgröße manchmal 0 war und dies die Berechnungen beeinträchtigte. IDK. Ich weiß nur, dass dies behoben wurde.

import UIKit

class SelfSizedCollectionView: UICollectionView {
    override func reloadData() {
        super.reloadData()
        self.invalidateIntrinsicContentSize()
    }

    override var intrinsicContentSize: CGSize {
        let s = self.collectionViewLayout.collectionViewContentSize
        return CGSize(width: max(s.width, 1), height: max(s.height,1))
    }

}
n13
quelle
2

Berechnen Sie zunächst die Anzahl der Zellen, multiplizieren Sie sie dann mit der Höhe der Zelle und geben Sie dann bei dieser Methode die Höhe zurück

    collectionView.frame = CGRectMake (x,y,w,collectionView.collectionViewLayout.collectionViewContentSize.height); //objective c
    //[collectionView reloadData];
   collectionView.frame = CGRect(x: 0, y: 0, width: width, height: collectionView.collectionViewLayout.collectionViewContentSize.height) // swift
Matloob Hasnain
quelle
Diese Methode gibt die Größe für eine bestimmte Zelle im Indexpfad zurück. Wenn Sie die Höhe auf noOfCell * heightOfCell festlegen, wird die Höhe aller Zellen festgelegt.
Georgi Boyadzhiev
@ Georgi Boyadzhiev, das stimmt.
charbinary
2
  1. Unterklasse UICollectionView wie folgt
  2. Löschen Sie ggf. die Höhenbeschränkung
  3. Aktivieren Sie die Eigengröße

- -

class ContentSizedCollectionView: UICollectionView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()            
        return CGSize(width: UIView.noIntrinsicMetric, height: collectionViewLayout.collectionViewContentSize.height)
    }
}
Jindřich Rohlík
quelle
0

Auf Ihrer UICollectionViewIhre Einschränkungen wie eingestellt Trailing, Leadingund Bottom:

UICollectionView-Einschränkungen

Wenn Sie sich meine Höhenbeschränkung genauer ansehen, da es sich nur um ein Storyboard handelt, damit ich keine Fehler bekomme, muss ich es tun Remove at build time. Die tatsächliche Höhenbeschränkung ist in meinem Code unten festgelegt.

UICollectionView-Höhenbeschränkung

Mein Code für DrawerCollectionView, der als Sammlungsansicht festgelegt ist Custom Class:

Benutzerdefinierte UICollectionView-Klasse

import UIKit

class DrawerCollectionView: UICollectionView {

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        heightAnchor.constraint(equalToConstant: contentSize.height).isActive = true
    }
}
George_E
quelle
Versucht, aber das hat bei mir nicht funktioniert. Die andere Unterklassenlösung von d4Rk arbeitete mit geringfügigen Änderungen
n13
0

arbeite für mich

    let heightRes = resCollectionView.collectionViewLayout.collectionViewContentSize.height
    foodHeightConstrant.constant = height.advanced(by: 1 )

    foodCollectionView.setNeedsLayout()
    foodCollectionView.layoutIfNeeded()
Peyman Jani
quelle
0

Holen Sie sich die Höhe der Zelle. Etwas wie das

let cellHeight = cell.frame.height

Holen Sie sich den Ursprung der Sammlungsansicht

let cvOrigin = collectionView.frame.origin

Ruft die Breite der Sammlungsansicht ab

let cvWidth = collectionView.bounds.width

Legen Sie den Rahmen der Inhaltsansicht fest

collection.frame = CGRect(x: cvOrigin.x, y: cvOrigin.y, width: cvWidth, height: cellHeight )
Aphoe
quelle
-1

Wenn Sie die Höhenbeschränkung der Sammlungsansicht festlegen. Beobachten Sie einfach die contentSizeÄnderung in viewDidLoad und aktualisieren Sie die Einschränkung.

        self.contentSizeObservation = collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, change in
            guard let `self` = self else { return }
            guard self.collectionView.contentSize != .zero else { return }
            self.collectionViewHeightLayoutConstraint.constant = self.collectionView.contentSize.height
        }
user25917
quelle