Skip to content

Wie bestimmt man die Abstände zwischen den Zellen in UICollectionView flowLayout

Diese Chronik wurde von Experten analysiert, sodass die Richtigkeit unseres Tutorials garantiert ist.

Lösung:

Update: Swift-Version dieser Antwort: https://github.com/fanpyi/UICollectionViewLeftAlignedLayout-Swift


Nach dem Vorbild von @matt habe ich seinen Code geändert, um sicherzustellen, dass die Elemente IMMER links ausgerichtet sind. Ich fand heraus, dass ein Element, das in einer eigenen Zeile landete, durch das Flusslayout zentriert wurde. Ich habe die folgenden Änderungen vorgenommen, um dieses Problem zu beheben.

Diese Situation würde nur dann auftreten, wenn die Zellen unterschiedlich breit sind, was zu einem Layout wie dem folgenden führen könnte. Die letzte Zeile ist immer linksbündig aufgrund des Verhaltens von UICollectionViewFlowLayoutDas Problem liegt bei Elementen, die sich selbst in einer beliebigen Zeile außer der letzten befinden.

Mit dem Code von @matt habe ich folgendes gesehen.

enter image description here

In diesem Beispiel sehen wir, dass die Zellen zentriert werden, wenn sie alleine in der Zeile stehen. Der folgende Code sorgt dafür, dass Ihre Auflistungsansicht so aussieht.

enter image description here

#import "CWDLeftAlignedCollectionViewFlowLayout.h"

const NSInteger kMaxCellSpacing = 9;

@implementation CWDLeftAlignedCollectionViewFlowLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
        if (nil == attributes.representedElementKind) {
            NSIndexPath* indexPath = attributes.indexPath;
            attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
        }
    }
    return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes* currentItemAttributes =
    [super layoutAttributesForItemAtIndexPath:indexPath];

    UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout sectionInset];

    CGRect currentFrame = currentItemAttributes.frame;

    if (indexPath.item == 0) { // first item of section
        currentFrame.origin.x = sectionInset.left; // first item of the section should always be left aligned
        currentItemAttributes.frame = currentFrame;

        return currentItemAttributes;
    }

    NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
    CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
    CGFloat previousFrameRightPoint = CGRectGetMaxX(previousFrame) + kMaxCellSpacing;

    CGRect strecthedCurrentFrame = CGRectMake(0,
                                              currentFrame.origin.y,
                                              self.collectionView.frame.size.width,
                                              currentFrame.size.height);

    if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) { // if current item is the first item on the line
        // the approach here is to take the current frame, left align it to the edge of the view
        // then stretch it the width of the collection view, if it intersects with the previous frame then that means it
        // is on the same line, otherwise it is on it's own new line
        currentFrame.origin.x = sectionInset.left; // first item on the line should always be left aligned
        currentItemAttributes.frame = currentFrame;
        return currentItemAttributes;
    }

    currentFrame.origin.x = previousFrameRightPoint;
    currentItemAttributes.frame = currentFrame;
    return currentItemAttributes;
}

@end

Um einen maximalen Abstand zwischen den Elementen zu erhalten, unterklassifizieren Sie UICollectionViewFlowLayout und überschreiben Sie layoutAttributesForElementsInRect: und layoutAttributesForItemAtIndexPath:.

Ein häufiges Problem ist zum Beispiel folgendes: Die Zeilen einer Auflistungsansicht sind rechts- und linksbündig, mit Ausnahme der letzten Zeile, die linksbündig ist. Sagen wir, wir wollen alle Zeilen linksbündig ausgerichtet werden, so dass der Abstand zwischen ihnen, sagen wir, 10 Punkte beträgt. Hier ist eine einfache Möglichkeit (in Ihrer UICollectionViewFlowLayout-Unterklasse):

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* arr = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* atts in arr) {
        if (nil == atts.representedElementKind) {
            NSIndexPath* ip = atts.indexPath;
            atts.frame = [self layoutAttributesForItemAtIndexPath:ip].frame;
        }
    }
    return arr;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes* atts =
    [super layoutAttributesForItemAtIndexPath:indexPath];

    if (indexPath.item == 0) // degenerate case 1, first item of section
        return atts;

    NSIndexPath* ipPrev =
    [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];

    CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
    CGFloat rightPrev = fPrev.origin.x + fPrev.size.width + 10;
    if (atts.frame.origin.x <= rightPrev) // degenerate case 2, first item of line
        return atts;

    CGRect f = atts.frame;
    f.origin.x = rightPrev;
    atts.frame = f;
    return atts;
}

Der Grund, warum dies so einfach ist, liegt darin, dass wir nicht wirklich die schwere Arbeit des Layouts durchführen; wir nutzen die Layoutarbeit, die UICollectionViewFlowLayout bereits für uns erledigt hat. Es hat bereits entschieden, wie viele Elemente in jede Zeile gehörene; wir lesen nur diese Zeilen und schieben die Elemente zusammen, wenn Sie sehen, was ich meine.

Es gibt ein paar Dinge zu beachten:

  1. Versuchen Sie, den Mindestabstand in IB zu ändern, aber lassen Sie den Cursor in diesem Feld. Beachten Sie, dass Xcode das Dokument nicht sofort als geändert markiert. Wenn Sie jedoch in ein anderes Feld klicken, stellt Xcode fest, dass das Dokument geändert wurde, und markiert es im Dateinavigator entsprechend. Achten Sie also darauf, nach einer Änderung mit der Tabulatortaste oder durch Klicken in ein anderes Feld zu wechseln.

  2. Speichern Sie Ihre Storyboard/xib-Datei, nachdem Sie eine Änderung vorgenommen haben, und stellen Sie sicher, dass Sie die App neu erstellen. Es ist nicht schwer, diesen Schritt zu verpassen, und dann fragt man sich, warum die Änderungen keine Auswirkungen zu haben scheinen.

  3. UICollectionViewFlowLayout hat eine minimumInteritemSpacing Eigenschaft, die Sie in IB einstellen. Aber der Delegat der Sammlung kann auch eine Methode haben, um die Abstände zwischen den Elementen zu bestimmen. Diese Methode übertrumpft die Eigenschaft des Layouts, wenn Sie sie also in Ihrem Delegaten implementieren, wird die Eigenschaft des Layouts nicht verwendet.

  4. Denken Sie daran, dass die Abstände dort eine Minimum ist. Abstand ist. Das Layout verwendet diese Zahl (unabhängig davon, ob sie aus der Eigenschaft oder aus der Delegatenmethode stammt) als kleinsten zulässigen Abstand, kann aber auch einen größeren Abstand verwenden, wenn in der Zeile noch Platz übrig ist. Wenn Sie also zum Beispiel den Mindestabstand auf 0 setzen, kann es sein, dass zwischen den Elementen noch ein paar Pixel übrig bleiben. Wenn Sie mehr Kontrolle über die genauen Abstände der Elemente haben möchten, sollten Sie ein anderes Layout verwenden (möglicherweise ein von Ihnen selbst erstelltes).

Posten Sie Rezensionen und Bewertungen

Wir würden uns freuen, wenn Sie diese Chronik weitergeben könnten, wenn es sich für Sie gelohnt hat.



Nutzen Sie unsere Suchmaschine

Suche
Generic filters

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.