UICollectionView hoogte automatisch aanpassen

Hoe pas ik het formaat van een UICollectionView op de juiste manier aan zodat de inhoud volledig wordt weergegeven? Ik heb veel dingen geprobeerd, waaronder het instellen van het frame, het aanroepen van reloadDataen het ongeldig maken van de lay-out:

self.collectionView.contentSize = CGSizeMake(300, 2000);
self.collectionView.frame = CGRectMake(0, 0, 300, 2000);
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];

maar niets hiervan heeft enig effect. Nadat ik op de knop heb gedrukt, zie ik nog steeds de eerste weergave, zoals deze:

verzamelingsweergave die alleen een deel van de inhoud toont nadat de grootte van het frame is gewijzigd

Ik heb een klein demoprogramma waarin ik een gegevensbron heb die 100 elementen produceert. In Interface Builder heb ik in eerste instantie de grootte van de UICollectionView op een kleine waarde gezet zodat niet alle elementen passen, daarna druk ik op een knop waarna bovenstaande code wordt uitgevoerd. Ik verwacht dat de UICollectionView nu alle elementen toont, maar dat is niet het geval.

BEWERKEN:Het demoprogramma is te vinden op https://github.com/mjdemilliano/TestUICollectionView.

EDIT2:ik heb gemerkt dat de frame-update op een gegeven moment verloren gaat, want als ik nogmaals op de knop druk, is het huidige frame terug naar de oude waarde. Na het toevoegen van enkele log-statements in de event-handler van de knop, is de log-output:

before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}

Ik begrijp niet waarom de framewijziging niet wordt bewaard, wat verandert deze.

Op een gegeven moment zal ik de hardgecodeerde waarden vervangen door waarden die zijn verkregen uit de stroomlay-out, maar ik wilde dat uitsluiten en mijn voorbeeld zo eenvoudig mogelijk houden.

Context: Wat ik uiteindelijk wil doen, is het volgende: ik heb een schuifbare weergave met verschillende bedieningselementen, zoals labels en afbeeldingen, en een collectieweergave met dynamische inhoud. Ik wil dat allemaal scrollen, niet alleen de collectieweergave, daarom gebruik ik niet de eigen scrollfaciliteiten van de collectieweergave, die prima werken.


Antwoord 1, autoriteit 100%

Ik heb dit uiteindelijk opgelost door alle problemen met de automatische lay-out op te lossen, waarbij de hoogte van de collectieweergave werd aangepast met een beperking. Vervolgens, wanneer ik weet dat de inhoud is gewijzigd, werk ik de waarde van de beperking bij met de waarde collectionView.contentSize.height:

self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;

Vervolgens wordt de grootte van de collectieweergave aangepast en gedraagt ​​deze zich netjes binnen de algemene scrollweergave. Ik heb het GitHub-testproject bijgewerkt met mijn wijzigingen.

Voor mij voelt het niet goed om dit te doen door de beperking handmatig bij te werken in plaats van iOS te kunnen vertellen: “maak de framehoogte van de collectieweergave zo groot als nodig is”, maar het is het beste wat ik kan doen. tot nu toe zijn gekomen. Post een beter antwoord als je er een hebt.


Antwoord 2, autoriteit 12%

Het lijkt goed te werken met een aangepaste UICollectionView-klasse.

class AutoSizedCollectionView: UICollectionView {
    override var contentSize: CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }
    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

Stel uw aangepaste klasse in de interfacebouwer in:

voer hier de afbeeldingsbeschrijving in

Op deze manier kunt u de intrinsieke grootte van uw collectieweergaven ook instellen op ‘placeholder’ in de interfacebuilder om te voorkomen dat u een hoogtebeperking hoeft in te stellen.

voer hier de afbeeldingsbeschrijving in

Ik hoop dat dit iemand anders helpt.


Antwoord 3, autoriteit 4%

Hier is mijn implementatie in Swift 3:

override func sizeThatFits(_ size: CGSize) -> CGSize {
    if (self.superview != nil) {
        self.superview?.layoutIfNeeded()
    }
    return collectionView.contentSize
}

Antwoord 4, autoriteit 2%

UICollectionViewFlowLayout *flowLayout;
flowLayout = [[UICollectionViewFlowLayout alloc]init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:NO];
[flowLayout setItemSize:CGSizeMake(322.0, 148.0)];  //important to leave no white space between the images
[self.collectionView setCollectionViewLayout:flowLayout];

Ik ontdekte dat automatische lay-out in het storyboard niet al te veel helpt. Een juiste instelling voor de UICollectionViewFlowLayout voor uw collectionView is de echte hulp. Als je de itemgrootte aanpast met setItemSize, krijg je mogelijk het gewenste resultaat.


Antwoord 5, autoriteit 2%

De eenvoudigste methode die ik heb gevonden is om de sizeThatFits:methoden te overschrijven zoals ze zijn:

- (CGSize)sizeThatFits:(CGSize)size
{
    if( self.superview )
        [self.superview layoutIfNeeded]; // to force evaluate the real layout
    return self.collectionViewLayout.collectionViewContentSize;
}

Antwoord 6

Hier is een manier om de hoogte van de CollectionView te binden via de intrinsieke grootte.
Ik heb het gebruikt om een ​​CollectionView binnen een TableView Cell (met dynamische celhoogte) op de juiste manier te dimensioneren. en het werkt perfect.

Voeg dit eerst toe aan uw UICollectionView-subklasse:

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

Bel vervolgens layoutIfNeeded() aan nadat u de gegevens opnieuw hebt geladen:

reloadData()
layoutIfNeeded()

Antwoord 7

  1. IBOutlet toevoegen voor CollectionView Height Constraint
    –> Zoals @IBOutlet zwakke var collectionViewHeight: NSLayoutConstraint!
  2. Voeg onderstaande geknipte code toe.

voer hier de afbeeldingsbeschrijving in


Antwoord 8

Je kunt mijn aangepaste AGCollectionViewklas uitproberen

  • Wijs een hoogtebeperking van collectionView toe met behulp van een storyboard of programmatisch.

– Wijs deze klas toe aan uw UICollectionView.

class AGCollectionView: UICollectionView {
    fileprivate var heightConstraint: NSLayoutConstraint!
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        self.associateConstraints()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }
    override open func layoutSubviews() {
        super.layoutSubviews()
        if self.heightConstraint != nil {
            self.heightConstraint.constant = floor(self.contentSize.height)
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint set size to fit content")
        }
    }
    func associateConstraints() {
        // iterate through height constraints and identify
        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

Antwoord 9

Voor mij is het nog eenvoudiger denk ik

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//add following code line after adding cells, before Return
...........
.........
scrollView.contentSize = = collectionView.contentSize;
//now scrollView size is equal to collectionView size. No matter how small or big it is.
return cell;
}

Other episodes