Zellenabstand in UICollectionView

197

Wie stelle ich den Zellenabstand in einem Abschnitt von ein UICollectionView? Ich weiß, dass es eine Eigenschaft gibt, die minimumInteritemSpacingich auf 5.0 gesetzt habe, aber der Abstand erscheint nicht 5.0. Ich habe die Flowout-Delegate-Methode implementiert.

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{

    return 5.0;
}

Trotzdem bekomme ich nicht das gewünschte Ergebnis. Ich denke, es ist der minimale Abstand. Gibt es keine Möglichkeit, den maximalen Abstand einzustellen?

Simulator sc

Vishal Singh
quelle
Hast du überprüft, ob die Delegate-Methode eingegeben wird oder nicht? durch Setzen des Haltepunktes ..
Prashant Nikam
Ja, es wird in den Delegaten eingegeben, in IB habe ich auch den minimalen Zellenabstand auf 5 gesetzt. Aber ich glaube nicht, dass der minimale Speicherplatz die Eigenschaft ist, die mir helfen wird, da er nur sicherstellen wird, dass der minimale Speicherplatz zwischen den Zellen 5 sein sollte, aber Wenn die Sammlungsansicht zusätzlichen Speicherplatz hat, wird dieser zusätzliche Speicherplatz verwendet. Es sollte so etwas wie einen maximalen Zellabstand geben
Vishal Singh
Ich habe das gleiche Problem. 5px scheint nicht zu funktionieren. Interessanterweise kann ich dies mit einer UITableView tun, aber nicht mit einer UICollectionView ...
Jerik
Ich habe es durch einige Berechnungen behoben. Ich werde es morgen veröffentlichen. :)
Vishal Singh
HINWEIS FÜR 2016 ist es so einfach: stackoverflow.com/a/28327193/294884
Fattie

Antworten:

145

Ich weiß, dass das Thema alt ist, aber falls jemand hier noch die richtige Antwort braucht, was Sie brauchen:

  1. Standard-Flow-Layout überschreiben.
  2. Fügen Sie eine Implementierung wie folgt hinzu:

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *answer = [super layoutAttributesForElementsInRect:rect];
    
        for(int i = 1; i < [answer count]; ++i) {
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = 4;
            NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
    
            if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.origin.x = origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }
        }
        return answer;
    }

Dabei kann MaximumSpacing auf einen beliebigen Wert eingestellt werden. Dieser Trick garantiert, dass der Abstand zwischen den Zellen genau gleich dem maximalen Abstand ist !!

iago849
quelle
Also, wo setzen wir das?
Jonny
1
Hey Jonny, erbe vom Standard-Flow-Layout und kopiere diese Methode einfach und füge sie in deine Klasse ein.
iago849
1
Beachten Sie, dass Sie mutableCopykein a erstellen müssen : Sie mutieren nicht den Inhalt des Arrays, sondern die darin enthaltenen Objekte.
Brock Boland
5
Vielleicht mache ich etwas falsch oder diese Idee funktioniert nicht zu 100%, denn wenn ich bis zum Ende
scrolle,
2
Guter Eintrag. Unter bestimmten Umständen ist ein Fehler aufgetreten, der die Formatierung der letzten Zeile des Layouts störte. Um das Problem zu beheben, habe ich ifeine zusätzliche Bedingung in AND geändert : if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota
190

Unterstützung der Ausgangsfrage. Ich habe versucht, den Abstand auf 5px auf dem zu bekommen, UICollectionViewaber das funktioniert nicht, auch mit einem UIEdgeInsetsMake(0,0,0,0)...

In einer UITableView kann ich dies tun, indem ich die x, y-Koordinaten in einer Reihe direkt spezifiziere ...

Geben Sie hier die Bildbeschreibung ein

Hier ist mein UICollectionView-Code:

#pragma mark collection view cell layout / size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return [self getCellSize:indexPath];  // will be w120xh100 or w190x100
    // if the width is higher, only one image will be shown in a line
}

#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {

    return 5.0;
}

Update: Mein Problem wurde mit dem folgenden Code behoben.

Geben Sie hier die Bildbeschreibung ein

ViewController.m

#import "ViewController.h"
#import "MagazineCell.h" // created just the default class. 

static NSString * const cellID = @"cellID";

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Collection view
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 30;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

    mCell.backgroundColor = [UIColor lightGrayColor];

    return mCell;
}

#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
    CGSize mElementSize = CGSizeMake(104, 104);
    return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
   // return UIEdgeInsetsMake(0,8,0,8);  // top, left, bottom, right
    return UIEdgeInsetsMake(0,0,0,0);  // top, left, bottom, right
}

@end
Jerik
quelle
Dies ist eine viel bessere Antwort. Werfen Sie einen Blick auf die Rückrufe, die Sie im UICollectionViewDelegateFlowLayout anpassen können, und sehen Sie, wie dies optimiert werden kann.
Cynistersix
1
Ich denke, dies kann nur funktionieren, wenn die Breite von Element + Abstand gleich der Breite von uicollectionview ist.
xi.lin
@ JayprakashDubey derzeit bin ich nicht in schnell fit. Versuch es zu machen. Viel Glück
Jerik
Wo geben Sie die Breite zwischen den Zellen von 5px an?
UKDataGeek
1
Eine viel bessere Antwort als die akzeptierte, vor allem, weil das Unterklassen von UICollectionViewLayout, um nur eine Methode zu überschreiben, wie ein Overkill erscheint und angesichts aller anderen Methoden, die überschrieben werden müssen, keine triviale Angelegenheit ist.
Cindeselia
80

Bei Verwendung eines horizontalen Flusslayouts erhielt ich auch einen Abstand von 10 Punkten zwischen den Zellen. Um den Abstand zu entfernen, musste ich sowohl auf Null setzen minimumLineSpacingals auch minimumInterItemSpacing.

UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;

Wenn alle Zellen dieselbe Größe haben, ist es einfacher und effizienter, die Eigenschaft direkt im Flow-Layout festzulegen, anstatt Delegate-Methoden zu verwenden.

Jason Moore
quelle
34
Überraschenderweise beeinflusst MinimumLineSpacing den horizontalen Abstand zwischen Zellen.
Matt H
4
ME auch, ich brauche einen horizontalen Bildlauf und einen Abstand von Null zwischen den Zellen, und MinimumLineSpacing = 0 ist der Schlüssel.
Wingzero
3
Ich konnte diesen Effekt erzielen, ohne ihn zu verwenden minimumInteritemSpacing. Durch einfaches Einstellen minimumLineSpacing = 0meines horizontalen Layouts wurde der horizontale Abstand zwischen den Elementen entfernt.
Ziewvater
1
Wenn Sie darüber nachdenken, ist der horizontale Abstand zwischen Elementen der Zeilenabstand für ein horizontal fließendes Layout. Der Zeilenabstand ist der vertikale Abstand zwischen Elementen in einem typischen vertikal fließenden Layout.
Lancejabr
62

Denken Sie daran, dass dies der minimale Zeilenabstand ist , nicht der minimale Abstand zwischen den Elementen oder der Zellenabstand. Weil die Bildlaufrichtung Ihrer collectionView HORIZONTAL ist .

Wenn es vertikal ist, müssen Sie den Zellenraum oder den Zwischenraum für den horizontalen Abstand zwischen den Zellen und den Zeilenabstand für den vertikalen Abstand zwischen den Zellen festlegen.

Objective-C-Version

- (CGFloat)collectionView:(UICollectionView *)collectionView
                       layout:(UICollectionViewLayout*)collectionViewLayout
    minimumLineSpacingForSectionAtIndex:(NSInteger)section
    {
        return 20;
    }

Schnelle Version:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 20
}
Vincent Joy
quelle
Jetzt ist das untere Leerzeichen weg, wenn ich 0 zurückgebe. Wie entferne ich den rechten Seitenraum?
Bangalore
Hey, ich habe deine Frage nicht sehr gut verstanden. Aber ich denke, insetForSectionAtIndex ist das, wonach Sie suchen. - (UIEdgeInsets) collectionView: (UICollectionView *) collectionView-Layout: (UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex: (NSInteger) section {return UIEdgeInsetsMake (5, 10, 5, 10); }
Vincent Joy
Der minimale Zeilenabstand ist sowohl horizontal als auch vertikal.
Swati
Du hast meinen Tag gerettet (Y).
Umair_UAS
Oh mein Wort! Ich kann das nicht glauben. Vielen Dank
Magoo
36

Versuchen Sie diesen Code, um sicherzustellen, dass zwischen jedem Element ein Abstand von 5 Pixel liegt:

- (UIEdgeInsets)collectionView:(UICollectionView *) collectionView 
                        layout:(UICollectionViewLayout *) collectionViewLayout 
        insetForSectionAtIndex:(NSInteger) section {

    return UIEdgeInsetsMake(0, 0, 0, 5); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *) collectionView
                   layout:(UICollectionViewLayout *) collectionViewLayout
  minimumInteritemSpacingForSectionAtIndex:(NSInteger) section {    
    return 5.0;
}
LASoft
quelle
Bitte formatieren Sie Ihren Code als Codeblock, damit er auf SO gut angezeigt wird.
Conduit
33

Schnelle Version der beliebtesten Antwort. Der Abstand zwischen den Zellen ist gleich cellSpacing.

class CustomViewFlowLayout : UICollectionViewFlowLayout {

    let cellSpacing:CGFloat = 4

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        if let attributes = super.layoutAttributesForElementsInRect(rect) {
        for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
        }
        return nil
    }
}
Vojtech Vrbka
quelle
super.layoutAttributesForElements (in: rect) gibt keine Idee zurück?
Ashok R
Wie alle anderen Methoden, die dies verwenden, funktioniert dies für mehrere Zeilen nicht ordnungsgemäß. Zwischen den Zeilen bleiben intermittierende Lücken im Rundungsfehlerstil bestehen, auch wenn die entsprechenden Delegierungsmethoden und -eigenschaften auf 0 gesetzt sind. Dies kann ein UICollectionView-Rendering-Problem sein.
Womble
30

Ich habe eine sehr einfache Möglichkeit gefunden, den Abstand zwischen Zellen oder Zeilen mithilfe von IB zu konfigurieren.

In wählen UICollectionView gerade von Storyboard / Xib Datei und klicken Sie auf Größe Inspector wie in Bild unten angegeben.

Geben Sie hier die Bildbeschreibung ein

Verwenden Sie zum programmgesteuerten Konfigurieren des Speicherplatzes die folgenden Eigenschaften.

1) Zum Einstellen des Abstandes zwischen den Zeilen.

[self.collectionView setMinimumLineSpacing:5];

2) Zum Einstellen des Abstands zwischen Elementen / Zellen.

[self.collectionView setMinimumInteritemSpacing:5];
Aamir
quelle
1
Dies ist der minimale Speicherplatz, der größer als der angegebene Wert und nicht immer der angegebene Wert ist.
Vishal Singh
21

Bitte beachten Sie den Eigenschaftsnamen MinimumInterItemSpacing . Dies ist der minimale Abstand zwischen den Elementen, nicht der genaue Abstand. Wenn Sie minimalInterItemSpacing auf einen bestimmten Wert festlegen, können Sie sicherstellen, dass der Abstand nicht kleiner als dieser Wert ist. Aber es besteht die Möglichkeit, einen höheren Wert zu erhalten.

Tatsächlich hängt der Abstand zwischen Elementen von mehreren Faktoren ab: itemSize und sectionInset . In der Sammlungsansicht werden die Inhalte basierend auf diesen Werten dynamisch platziert. Sie können also den genauen Abstand nicht gewährleisten. Sie sollten einige Versuche mit SectionInset und MinimumInterItemSpacing durchführen .

Anil Varghese
quelle
1
@ Alle Randinsekten? : D
NightFury
10
Möglicherweise gibt es Fehler in Ihrem AbschnittInsects.
Nestor
24
Insekt == Bug && Insekt! = Einschub :)
Nestor
16

Antwort für Swift 3.0, Xcode 8

1.Stellen Sie sicher, dass Sie den Delegaten für die Sammlungsansicht festlegen

class DashboardViewController: UIViewController {
    @IBOutlet weak var dashboardCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardCollectionView.delegate = self
    }
}

2. Implementieren Sie das UICollectionViewDelegateFlowLayout- Protokoll, nicht UICollectionViewDelegate.

extension DashboardViewController: UICollectionViewDelegateFlowLayout {
    fileprivate var sectionInsets: UIEdgeInsets {
        return .zero
    }

    fileprivate var itemsPerRow: CGFloat {
        return 2
    }

    fileprivate var interitemSpace: CGFloat {
        return 5.0
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let sectionPadding = sectionInsets.left * (itemsPerRow + 1)
        let interitemPadding = max(0.0, itemsPerRow - 1) * interitemSpace
        let availableWidth = collectionView.bounds.width - sectionPadding - interitemPadding
        let widthPerItem = availableWidth / itemsPerRow

        return CGSize(width: widthPerItem, height: widthPerItem)
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0.0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return interitemSpace
    }
}
Vadim Bulavin
quelle
1
Denken Sie, Sie können die Öffentlichkeit dort entfernen. Sollte gut funktionieren und mit allen anderen Funktionen übereinstimmen.
Edward Potter
Würde dies für die vertikale Bildlaufsammlungsansicht funktionieren? Ich habe eine Sammlungsansicht, in der 2 Zellen horizontal auf Geräten wie iPhone 6s und 6s Plus angezeigt werden sollen, aber nur eine Zelle für weniger als 5s, 5 und SE. Mein aktueller Code funktioniert, aber in 6s Plus-Geräten ist die Lücke zwischen den Zellen einfach zu groß und sieht hässlich aus. Ich versuche, diese Lücke zu verringern, und das ist die einzige Voraussetzung, da alle anderen Geräte gemäß meinem Design funktionieren.
AnBisw
11

Einfacher Code für den Abstand

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value
AMayes
quelle
2
Für den horizontalen Zellenabstand sollte Folgendes verwendet werden: MinimumLineSpacing
Alfi
9

Die gewählte Antwort (und auch die schnelle Version ) hat ein kleines Problem: Es wird einen großen Abstand auf der rechten Seite geben.

Dies liegt daran, dass das Flusslayout so angepasst wird, dass der Zellenabstand exakt ist und ein Float übrig bleibt .

Meine Lösung besteht darin, den Abschnittseinsatz so zu manipulieren, dass der Abschnitt mittig ausgerichtet ist und der Abstand genau den Angaben entspricht.

In der Abbildung unten beträgt der Abstand zwischen Element und Zeile genau 8pt, während der Abschnitt links und rechts größer als 8pt ist (um ihn mittig auszurichten):

gleichmäßig verteilte Zellen

Schneller Code als solcher:

private let minItemSpacing: CGFloat = 8
private let itemWidth: CGFloat      = 100
private let headerHeight: CGFloat   = 32

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Create our custom flow layout that evenly space out the items, and have them in the center
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
    layout.minimumInteritemSpacing = minItemSpacing
    layout.minimumLineSpacing = minItemSpacing
    layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)

    // Find n, where n is the number of item that can fit into the collection view
    var n: CGFloat = 1
    let containerWidth = collectionView.bounds.width
    while true {
        let nextN = n + 1
        let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
        if totalWidth > containerWidth {
            break
        } else {
            n = nextN
        }
    }

    // Calculate the section inset for left and right. 
    // Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
    let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    collectionView.collectionViewLayout = layout
}
Samwize
quelle
1
Ich erhalte eine 'NSInvalidArgumentException', Grund: '*** setObjectForKey: Objekt kann nicht null sein (Schlüssel: <NSIndexPath: 0xc000000000000016> {Länge = 2, Pfad = 0 - 0})' nicht erfasste Ausnahme.
DaftWooly
... wenn ich mich nicht irre, entspricht Ihre while-Schleife: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly
Ich habe den Code nicht so verwendet, wie er ist, aber dies gab mir die beste Referenz für die Implementierung meines Outflow-Layouts für die Sammlungsansicht. prost
Dima Gimburg
8

Definieren Sie das UICollectionViewDelegateFlowLayoutProtokoll in Ihrer Header-Datei.

Implementieren Sie die folgende UICollectionViewDelegateFlowLayoutProtokollmethode:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(5, 5, 5, 5);
}

Klicken Sie hier , um die Apple-Dokumentation der UIEdgeInsetMakeMethode anzuzeigen.

Salman Zaidi
quelle
3

Wenn Sie den Abstand anpassen möchten, ohne die tatsächliche Zellengröße zu berühren, ist dies die Lösung, die für mich am besten funktioniert hat. #xcode 9 # tvOS11 # iOS11 #swift

Ändern Sie in UICollectionViewDelegateFlowLayout die Implementierung der nächsten Methoden. Der Trick besteht darin, dass Sie beide verwenden müssen, und die Dokumentation hat mich nicht wirklich dazu veranlasst, in diese Richtung zu denken. : D.

open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return cellSpacing
}

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return cellSpacing
}
Boris
quelle
3

Storyboard-Ansatz

Wählen Sie CollectionView in Ihrem Storyboard aus, gehen Sie zum Größeninspektor und legen Sie den Mindestabstand für Zellen und Linien auf 5 fest

Swift 5 programmgesteuert

lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        //Provide Width and Height According to your need
        let width = UIScreen.main.bounds.width / 4
        let height = UIScreen.main.bounds.height / 10
        layout.itemSize = CGSize(width: width, height: height)

        //For Adjusting the cells spacing
        layout.minimumInteritemSpacing = 5
        layout.minimumLineSpacing = 5

        return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    }()
Shubham Mishra
quelle
2

Ich verwende Monotouch, daher sind die Namen und der Code etwas unterschiedlich. Sie können dies jedoch tun, indem Sie sicherstellen, dass die Breite der Sammlungsansicht (x * Zellenbreite) + (x-1) * MinimumSpacing mit x = Betrag entspricht von Zellen pro Zeile.

Führen Sie einfach die folgenden Schritte aus, die auf Ihrem MinimumInteritemSpacing und der Breite der Zelle basieren

1) Wir berechnen die Anzahl der Elemente pro Zeile basierend auf der Zellengröße + den aktuellen Einfügungen + dem Mindestabstand

float currentTotalWidth = CollectionView.Frame.Width - Layout.SectionInset.Left - Layout.SectionInset.Right (Layout = flowlayout)
int amountOfCellsPerRow = (currentTotalWidth + MinimumSpacing) / (cell width + MinimumSpacing)

2) Jetzt haben Sie alle Informationen, um die erwartete Breite für die Sammlungsansicht zu berechnen

float totalWidth =(amountOfCellsPerRow * cell width) + (amountOfCellsPerRow-1) * MinimumSpacing

3) Der Unterschied zwischen der aktuellen Breite und der erwarteten Breite beträgt also

float difference = currentTotalWidth - totalWidth;

4) Passen Sie nun die Einfügungen an (in diesem Beispiel fügen wir sie rechts hinzu, sodass die linke Position der Sammlungsansicht gleich bleibt

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;
Matt
quelle
2

Ich habe eine horizontale UICollectionViewund untergeordneteUICollectionViewFlowLayout . Die Sammlungsansicht verfügt über große Zellen und zeigt jeweils nur eine Zeile an. Die Sammlungsansicht passt zur Breite des Bildschirms.

Ich habe die Antwort von iago849 ausprobiert und es hat funktioniert, aber dann habe ich herausgefunden, dass ich seine Antwort nicht einmal brauchte. Aus irgendeinem Grund minimumInterItemSpacingbewirkt das Einstellen von nichts. Der Abstand zwischen meinen Elementen / Zellen kann vollständig durch gesteuert werdenminimumLineSpacing .

Ich bin mir nicht sicher, warum es so funktioniert, aber es funktioniert.

user3344977
quelle
1
Dies scheint wahr zu sein - seltsamerweise ist der Wert "Linien" tatsächlich das Trennzeichen zwischen Elementen bei einem horizontalen Layout.
Fattie
Hey @ user3344977 - schöner Fund. Ich habe beschlossen, dieses Problem in eine separate Frage zu unterteilen, die sich direkt mit horizontalen Bildlaufsammlungsansichten befasst, damit sie für einige Personen leichter zu finden sind. Ich verweise dort auf Ihre Antwort. Meine Frage ist hier: stackoverflow.com/q/61774415/826946
Andy Weinstein
1

Ich bin auf ein ähnliches Problem wie OP gestoßen. Leider hat die akzeptierte Antwort bei mir nicht funktioniert, da der Inhalt der collectionViewnicht richtig zentriert wäre. Deshalb habe ich eine andere Lösung gefunden, die nur erfordert, dass alle Elemente in collectionViewder gleichen Breite sind , was in der Frage der Fall zu sein scheint:

#define cellSize 90

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    float width = collectionView.frame.size.width;
    float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    int numberOfCells = (width + spacing) / (cellSize + spacing);
    int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;

    return UIEdgeInsetsMake(0, inset, 0, inset);
}

Dieser Code stellt sicher, dass der von zurückgegebene Wert ...minimumInteritemSpacing...der genaue Abstand zwischen allen ist, collectionViewCellund garantiert außerdem, dass die Zellen alle zusammen in der zentriert werdencollectionView

luk2302
quelle
Das ist ziemlich toll. Aber ich habe mich gefragt, ob eine ähnliche Lösung auf den vertikalen Abstand zwischen Elementen angewendet werden kann
p0lAris
Vertikaler Abstand für den Fall, dass Sie horizontal scrollen?
luk2302
1

Die obige Lösung von vojtech-vrbka ist korrekt, löst jedoch eine Warnung aus:

Warnung: UICollectionViewFlowLayout hat eine nicht übereinstimmende Frame-Nichtübereinstimmung für den zwischen dem Indexpfad zwischengespeicherten Wert: Dies tritt wahrscheinlich auf, weil die Unterklasse Layout des Flusslayouts die von UICollectionViewFlowLayout zurückgegebenen Attribute ändert, ohne sie zu kopieren

Der folgende Code sollte das Problem beheben:

class CustomViewFlowLayout : UICollectionViewFlowLayout {

   let cellSpacing:CGFloat = 4

   override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
       let original = super.layoutAttributesForElementsInRect(rect)

       if let original = original {
           let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]

           for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
       }
       return nil
   }
}
Torrao
quelle
2
Wie die anderen Antworten auf SO, die diesen Ansatz verwenden, funktioniert dies auch für das Anpassen von Zellen über die Breite der collectionView, aber es bleiben immer noch intermittierende Lücken mit variabler Höhe zwischen den Zeilen. Dies kann eine Einschränkung der Art und Weise sein, wie CollectionView tatsächlich rendert.
Womble
1

Swift 3 Version

Erstellen Sie einfach eine UICollectionViewFlowLayout-Unterklasse und fügen Sie diese Methode ein.

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let answer = super.layoutAttributesForElements(in: rect) else { return nil }

        for i in 1..<answer.count {
            let currentAttributes = answer[i]
            let previousAttributes = answer[i - 1]

            let maximumSpacing: CGFloat = 8
            let origin = previousAttributes.frame.maxX

            if (origin + maximumSpacing + currentAttributes.frame.size.width < self.collectionViewContentSize.width && currentAttributes.frame.origin.x > previousAttributes.frame.origin.x) {
                var frame = currentAttributes.frame
                frame.origin.x = origin + maximumSpacing
                currentAttributes.frame = frame
            }
        }

        return answer
}
topLayoutGuide
quelle
Dies funktioniert für die horizontale Anpassung, aber die Lücken zwischen den Zeilen bleiben bestehen, auch wenn minimalLineSpacingForSectionAt auf 0 und layout.minimumLineSpacing auf 0 gesetzt ist. Außerdem wird die App durch Berühren in der collectionView zum Absturz gebracht, da die erste Schleife unterbrochen wird der Reichweite.
Womble
1

Ich habe die Antwort von iago849 ausprobiert und es hat funktioniert.

Swift 4

open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let answer = super.layoutAttributesForElements(in: rect) else {
        return nil
    }
    let count = answer.count
    for i in 1..<count {
        let currentLayoutAttributes = answer[i]
        let prevLayoutAttributes = answer[i-1]
        let origin = prevLayoutAttributes.frame.maxX
        if (origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x {
            var frame = currentLayoutAttributes.frame
            frame.origin.x = origin + CGFloat(spacing)
            currentLayoutAttributes.frame = frame
        }
    }
    return answer
}

Hier ist der Link für das Github-Projekt. https://github.com/vishalwaka/MultiTags

Vishalwaka
quelle
0

Frühere Versionen funktionierten nicht wirklich mit Abschnitten> 1. Meine Lösung wurde also hier gefunden: https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ . Für die Faulen:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
    var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
    // use a value to keep track of left margin
    var leftMargin: CGFloat = 0.0;
    for attributes in attributesForElementsInRect! {
        let refAttributes = attributes 
        // assign value if next row
        if (refAttributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left
        } else {
            // set x position of attributes to current margin
            var newLeftAlignedFrame = refAttributes.frame
            newLeftAlignedFrame.origin.x = leftMargin
            refAttributes.frame = newLeftAlignedFrame
        }
        // calculate new value for current margin
        leftMargin += refAttributes.frame.size.width + 10
        newAttributesForElementsInRect.append(refAttributes)
    }

    return newAttributesForElementsInRect
}
Mantas Laurinavičius
quelle
0

Ich habe ein Problem mit der akzeptierten Antwort, daher habe ich sie aktualisiert. Dies funktioniert für mich:

.h

@interface MaxSpacingCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,assign) CGFloat maxCellSpacing;
@end

.m

@implementation MaxSpacingCollectionViewFlowLayout

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    if (attributes.count <= 0) return attributes;

    CGFloat firstCellOriginX = ((UICollectionViewLayoutAttributes *)attributes[0]).frame.origin.x;

    for(int i = 1; i < attributes.count; i++) {
        UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
        if (currentLayoutAttributes.frame.origin.x == firstCellOriginX) { // The first cell of a new row
            continue;
        }

        UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1];
        CGFloat prevOriginMaxX = CGRectGetMaxX(prevLayoutAttributes.frame);
        if ((currentLayoutAttributes.frame.origin.x - prevOriginMaxX) > self.maxCellSpacing) {
            CGRect frame = currentLayoutAttributes.frame;
            frame.origin.x = prevOriginMaxX + self.maxCellSpacing;
            currentLayoutAttributes.frame = frame;
        }
    }
    return attributes;
}

@end
Yun CHEN
quelle
0

Meine Lösung im Swift 3Zelllinienabstand wie bei Instagram:

Geben Sie hier die Bildbeschreibung ein

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.backgroundColor = UIColor.rgb(red: 227, green: 227, blue: 227)
    cv.showsVerticalScrollIndicator = false
    layout.scrollDirection = .vertical
    layout.minimumLineSpacing = 1
    layout.minimumInteritemSpacing = 1
    return cv
}()

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    switch UIDevice.current.modelName {
    case "iPhone 4":
        return CGSize(width: 106, height: 106)
    case "iPhone 5":
        return CGSize(width: 106, height: 106)
    case "iPhone 6,7":
        return CGSize(width: 124, height: 124)
    case "iPhone Plus":
        return CGSize(width: 137, height: 137)
    default:
        return CGSize(width: frame.width / 3, height: frame.width / 3)
    }
}

So erkennen Sie das Gerät programmgesteuert: https://stackoverflow.com/a/26962452/6013170

Zhanserik
quelle
0

Wenn Sie eine horizontale Sammlungsansicht erstellen, müssen Sie die Eigenschaft festlegen, um Platz zwischen den Zellen zu schaffen minimumLineSpacing.

Shanu Singh
quelle
-1

Versuchen Sie, mit dieser Methode herumzuspielen:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

    UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?);

    return insets;
}
Nikola Kirev
quelle
2
Dies funktioniert nur für den Abstand zwischen Abschnitten, nicht für Zellen
Diego A. Rincon