Odstępy między komórkami w UICollectionView

197

Jak ustawić odstępy między komórkami w sekcji UICollectionView? Wiem, że istnieje właściwość, minimumInteritemSpacingktórą ustawiłem na 5.0, ale odstępy nie pojawiają się 5.0. Wdrożyłem metodę delegowania przepływu.

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

    return 5.0;
}

wciąż nie otrzymuję pożądanego rezultatu. Myślę, że to minimalne odstępy. Czy nie ma sposobu na ustawienie maksymalnego odstępu?

symulator sc

Vishal Singh
źródło
sprawdziłeś, czy wchodzi w metodę delegowania czy nie? ustawiając punkt przerwania ..
Prashant Nikam
tak, wchodzi do delegata, w IB również ustawiłem minimalny odstęp między komórkami na 5. Ale nie sądzę, że minimalna przestrzeń jest właściwością, która mi pomoże, ponieważ upewni się tylko, że minimalna przestrzeń między komórkami powinna wynosić 5, ale jeśli widok kolekcji ma dodatkową przestrzeń, to wykorzysta tę dodatkową przestrzeń. Powinno być coś w rodzaju maksymalnego odstępu między komórkami
Vishal Singh
Mam ten sam problem. 5px wydaje się nie działać. Interesująco mogę to zrobić za pomocą UITableView, ale nie za pomocą UICollectionView ...
jerik
Naprawiłem to, wykonując kilka obliczeń .. opublikuję go jutro. :)
Vishal Singh
UWAGA NA 2016 r . To takie proste: stackoverflow.com/a/28327193/294884
Fattie

Odpowiedzi:

145

Wiem, że temat jest stary, ale na wypadek, gdyby ktoś nadal potrzebował poprawnej odpowiedzi, czego potrzebujesz:

  1. Zastąp standardowy układ przepływu.
  2. Dodaj implementację w ten sposób:

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

gdzie maximumSpacing można ustawić na dowolną preferowaną wartość. Ta sztuczka gwarantuje, że odstęp między komórkami byłby DOKŁADNIE równy maksymalnej odległości!

iago849
źródło
Gdzie to umieścimy?
Jonny
1
Hej Jonny, odziedzicz po standardowym układzie przepływu i po prostu skopiuj i wklej tę metodę do swojej klasy.
iago849
1
Zauważ, że nie musisz tworzyć mutableCopy: nie modyfikujesz zawartości tablicy, ale mutujesz obiekty w niej zawarte.
Brock Boland
5
może robię coś źle lub ten pomysł nie działa w 100%, ponieważ kiedy przewijam do końca, widzę, że niektóre komórki nakładają się na siebie :(
pash3r
2
Wspaniały post. W niektórych przypadkach napotkałem błąd, który zakłócił formatowanie ostatniego wiersza układu. Aby rozwiązać, zmieniłem na ifAND dodatkowy warunek: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota,
190

Wspieranie pierwszego pytania. Próbowałem uzyskać odstępy do 5 pikseli na, UICollectionViewale to nie działa, również z UIEdgeInsetsMake(0,0,0,0)...

Na UITableView mogę to zrobić, bezpośrednio określając współrzędne x, y w rzędzie ...

wprowadź opis zdjęcia tutaj

Oto mój kod UICollectionView:

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

Aktualizacja: Rozwiązałem mój problem za pomocą następującego kodu.

wprowadź opis zdjęcia tutaj

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
źródło
To jest znacznie lepsza odpowiedź. Spójrz na wywołania zwrotne, które możesz dostosować w UICollectionViewDelegateFlowLayout, a zobaczysz, jak można to poprawić.
cynistersix
1
I cienkie to może działać tylko wtedy, gdy szerokość elementu + odstępy są równe szerokości widoku uicollection.
xi.lin,
@JayprakashDubey obecnie nie pasuję do szybkiego. Musisz tego spróbować. Powodzenia
jerik
Gdzie określasz szerokość między komórkami 5px?
UKDataGeek
1
Znacznie lepsza odpowiedź niż zaakceptowana, głównie dlatego, że podklasowanie UICollectionViewLayout tylko w celu zastąpienia jednej metody wydaje się przesadą i nie jest to banalna sprawa biorąc pod uwagę wszystkie inne metody, które należy zastąpić.
Cindeselia
80

Korzystając z układu poziomego przepływu, uzyskiwałem również odstęp 10 punktów między komórkami. Aby usunąć odstępy, musiałem ustawić minimumLineSpacingtak samo, jak minimumInterItemSpacingzero.

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

Ponadto, jeśli wszystkie komórki mają ten sam rozmiar, łatwiej i wydajniej jest ustawić właściwość w układzie przepływu bezpośrednio zamiast metod delegowania.

Jason Moore
źródło
34
Co zaskakujące, minimumLineSpacing wpływa na poziomą przestrzeń między komórkami.
Matt H
4
Ja też potrzebuję przewijania w poziomie i zerowego odstępu między komórkami, a minimumLineSpacing = 0 jest kluczem.
Wingzero,
3
Byłem w stanie uzyskać ten efekt bez użycia minimumInteritemSpacing. Właśnie ustawienie minimumLineSpacing = 0mojego poziomego układu usunęło poziome odstępy między przedmiotami.
Ziewvater
1
Jeśli się nad tym zastanowić, odległość w poziomie między elementami JEST odstępem między wierszami dla układu płynącego w poziomie. Odstępy między wierszami to odległość pionowa między elementami w typowym układzie pionowo płynącym.
lancejabr
62

Pamiętaj, że jest to minimalna przestrzeń między wierszami, a nie minimalne odstępy między elementami lub komórki. Ponieważ kierunek przewijania kolekcji collectionView to POZIOME .

Jeśli jest pionowy, musisz ustawić przestrzeń komórki lub przestrzeń między elementami dla poziomej przestrzeni między komórkami i odstępów między liniami dla pionowej przestrzeni między komórkami.

Wersja C celu

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

Wersja szybka:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 20
}
Vincent Joy
źródło
teraz dolna przestrzeń zniknęła, gdy zwracam 0; jak usunąć prawą boczną przestrzeń?
Bangalore,
Hej, nie zrozumiałem dobrze twojego pytania. Ale myślę, że insetForSectionAtIndex jest tym, czego szukasz. - (UIEdgeInsets) collectionView: (UICollectionView *) collectionView layout: (UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex: sekcja (NSInteger) {return UIEdgeInsetsMake (5, 10, 5, 10); }
Vincent Joy,
Jest to minimalny odstęp między wierszami zarówno w poziomie, jak i w pionie.
Swati
Uratowałeś mi dzień (Y).
Umair_UAS
Och, moje słowo! Nie mogę w to uwierzyć. Dzięki
Magoo,
36

Wypróbuj ten kod, aby upewnić się, że odstęp między pikselami wynosi 5 pikseli:

- (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
źródło
Sformatuj kod jako blok kodu, aby ładnie wyświetlał się na SO.
Przewód
33

Szybka wersja najpopularniejszej odpowiedzi. Odstęp między komórkami będzie równy 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
źródło
super.layoutAttributesForElements (in: rect) zwraca zero pomysłów?
Ashok R
Podobnie jak wszystkie inne metody, które tego używają, nie działa to poprawnie dla wielu wierszy. Pomiędzy wierszami pozostaną przerywane luki w stylu błędu zaokrąglania, nawet przy odpowiednich metodach delegowania i właściwościach ustawionych na 0. Może to być problem z renderowaniem UICollectionView.
Womble,
30

Znalazłem bardzo łatwy sposób konfigurowania odstępów między komórkami lub wierszami za pomocą IB.

Wystarczy wybrać UICollectionView z pliku storyboard / Xib i kliknąć w Inspektorze wielkości, jak określono na poniższym obrazku.

wprowadź opis zdjęcia tutaj

Aby programowo skonfigurować przestrzeń, użyj następujących właściwości.

1) Do ustawienia odstępu między rzędami.

[self.collectionView setMinimumLineSpacing:5];

2) Do ustawienia odstępu między elementami / komórkami.

[self.collectionView setMinimumInteritemSpacing:5];
Aamir
źródło
1
To minimalna ilość miejsca, która będzie większa niż określona wartość, a nie zawsze określona wartość.
Vishal Singh
21

Należy zwrócić uwagę na nazwę właściwości minimumInterItemSpacing . Będzie to minimalny odstęp między przedmiotami, a nie dokładny odstęp. Jeśli ustawisz minimumInterItemSpacing na pewną wartość, możesz mieć pewność, że odstępy nie będą mniejsze niż ta wartość. Ale jest szansa na wyższą wartość.

W rzeczywistości odstępy między elementami zależą od kilku czynników itemSize i sectionInset . Widok kolekcji dynamicznie umieszcza zawartość na podstawie tych wartości. Nie możesz więc zapewnić dokładnego odstępu. Powinieneś zrobić kilka prób i błędów z sectionInset i minimumInterItemSpacing .

Anil Varghese
źródło
1
@Inne owady na krawędzi? : D
NightFury
10
W sekcji Owady mogą znajdować się błędy.
Nestor
24
insect == bug && insect! = wstawka :)
Nestor
16

Odpowiedz na Swift 3.0, Xcode 8

1.Upewnij się, że ustawiłeś delegowanie widoku kolekcji

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

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

2. Zaimplementuj protokół UICollectionViewDelegateFlowLayout , a nie 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
źródło
1
Myślisz, że możesz tam usunąć publiczność. Powinien działać dobrze i zgodny ze wszystkimi innymi funkcjami.
Edward Potter
Czy to zadziała w widoku kolekcji przewijania w pionie? Mam widok kolekcji, w którym powinien pokazywać 2 komórki poziomo na urządzeniach takich jak iPhone 6s i 6s Plus, ale powinien pokazywać tylko jedną komórkę dla czegoś niższego, tj. 5s, 5 i SE. Mój obecny kod działa, ale w urządzeniu 6s Plus przerwa między komórkami jest po prostu zbyt duża i wygląda brzydko, a ja próbuję ją zmniejszyć, a to jedyny wymóg, ponieważ wszystkie inne urządzenia działają zgodnie z moim projektem.
AnBisw
11

Prosty kod odstępów

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value
AMayes
źródło
3
Do poziomych odstępów między komórkami należy użyć: minimumLineSpacing
Alfi
9

Głosowało odpowiedź (a także wersja szybka ) ma mały problem: nie będzie duży odstęp po prawej stronie.

Wynika to z tego, że układ przepływu jest dostosowywany, aby uzyskać dokładne odstępy między komórkami, z zachowaniem swobodnego ruchu w lewo .

Moim rozwiązaniem jest manipulowanie wstawką sekcji, aby sekcja była wyrównana do środka, ale odstępy są dokładnie takie, jak określono.

Na poniższym zrzucie ekranu odstęp między pozycjami / liniami wynosi dokładnie 8 punktów, a wstawka sekcji lewej i prawej będzie większa niż 8 punktów (aby wyrównać do środka):

równomiernie rozmieszczone komórki

Szybki kod jako taki:

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
źródło
1
Dostaję „NSInvalidArgumentException”, powód: „*** setObjectForKey: obiekt nie może być zerowy (klucz: <NSIndexPath: 0xc000000000000016> {długość = 2, ścieżka = 0 - 0})” niewyłapany wyjątek.
DaftWooly
... jeśli się nie mylę, twoja pętla while jest równoważna: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly,
Nie użyłem kodu w obecnej postaci, ale dało mi to najlepsze odniesienie do implementacji mojego układu przepływu wyjściowego dla widoku kolekcji. na zdrowie
Dima Gimburg,
8

Definiować UICollectionViewDelegateFlowLayout protokół w pliku nagłówka.

Zaimplementuj następującą metodę UICollectionViewDelegateFlowLayoutprotokołu:

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

Kliknij tutaj, aby zobaczyć dokumentację Apple dotyczącą UIEdgeInsetMakemetody.

Salman Zaidi
źródło
3

Jeśli chcesz dostosować odstępy bez dotykania rzeczywistego rozmiaru komórki, jest to najlepsze rozwiązanie dla mnie. #xcode 9 # tvOS11 # iOS11 #swift

Tak więc w UICollectionViewDelegateFlowLayout zmień implementację następnych metod, sztuczka polega na tym, że musisz użyć obu z nich, a dokumentacja tak naprawdę nie wskazywała na mnie do myślenia w tym kierunku. :RE

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
źródło
3

Podejście do scenorysu

Wybierz CollectionView w serii ujęć i przejdź do inspektora rozmiarów i ustaw minimalne odstępy dla komórek i linii na 5

Swift 5 programowo

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
źródło
2

Używam monotouch, więc nazwy i kod będą nieco inne, ale możesz to zrobić, upewniając się, że szerokość widoku kolekcji jest równa (x * szerokość komórki) + (x-1) * Minimalna odległość od x = kwota komórek na wiersz.

Wykonaj następujące kroki na podstawie minimalnego odstępu między parametrami i szerokości komórki

1) Obliczamy ilość elementów na wiersz na podstawie wielkości komórki + bieżące wstawki + minimalne odstępy

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

2) Teraz masz wszystkie informacje, aby obliczyć oczekiwaną szerokość dla widoku kolekcji

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

3) Zatem różnica między bieżącą szerokością a oczekiwaną szerokością wynosi

float difference = currentTotalWidth - totalWidth;

4) Teraz dostosuj wstawki (w tym przykładzie dodajemy go po prawej stronie, więc lewa pozycja widoku kolekcji pozostaje taka sama

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;
Matt
źródło
2

Mam poziomy UICollectionViewi podklasęUICollectionViewFlowLayout . Widok kolekcji ma duże komórki i pokazuje tylko jeden rząd na raz, a widok kolekcji pasuje do szerokości ekranu.

Próbowałem odpowiedzi iago849 i zadziałało, ale potem okazało się, że nawet nie potrzebowałem jego odpowiedzi. Z jakiegoś powodu ustawienie minimumInterItemSpacingnic nie robi. Odstępy między moimi przedmiotami / komórkami można całkowicie kontrolowaćminimumLineSpacing .

Nie jestem pewien, dlaczego tak działa, ale działa.

użytkownik3344977
źródło
1
wydaje się to być prawdą - co dziwne, wartość „linii” jest w rzeczywistości separatorem między elementami w przypadku układu poziomego.
Fattie
Hej @ user3344977 - fajne znalezisko. Postanowiłem podzielić ten problem na osobne pytanie, które bezpośrednio odnosi się do poziomych widoków kolekcji przewijania, aby łatwiej było je znaleźć niektórym osobom. Odsyłam tam twoją odpowiedź. Moje pytanie jest tutaj: stackoverflow.com/q/61774415/826946
Andy Weinstein
1

Natknąłem się na podobny problem jak OP. Niestety zaakceptowana odpowiedź nie działała dla mnie, ponieważ treść collectionViewnie byłaby odpowiednio wyśrodkowana. Dlatego wpadłem na inne rozwiązanie, które wymaga tylko, aby wszystkie elementy collectionViewbyły tej samej szerokości , co wydaje się mieć miejsce w pytaniu:

#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);
}

Ten kod zapewni, że zwracana wartość ...minimumInteritemSpacing...będzie dokładnym odstępem między wszystkimi, collectionViewCella ponadto zagwarantuje, że wszystkie komórki zostaną wyśrodkowane wcollectionView

luk2302
źródło
To fajnie. Ale zastanawiałem się, czy podobne rozwiązanie można zastosować do pionowych odstępów między elementami
p0lAris
Odstępy w pionie w przypadku przewijania w poziomie?
luk2302
1

Powyższe rozwiązanie przez Vojtech-Vrbka jest poprawna, ale wyzwala ostrzeżenie:

ostrzeżenie: UICollectionViewFlowLayout ma niedopasowane ramki pamięci podręcznej dla ścieżki indeksu - wartość buforowana: Prawdopodobnie dzieje się tak, ponieważ układ podklasy układu przepływu modyfikuje atrybuty zwracane przez UICollectionViewFlowLayout bez kopiowania ich

Poniższy kod powinien to naprawić:

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
źródło
2
Podobnie jak inne odpowiedzi w SO, które wykorzystują to podejście, działa to tak, aby dopasować komórki na całej szerokości collectionView, ale między wierszami nadal występują przerywane przerwy o zmiennej wysokości. Może to być ograniczenie sposobu, w jaki CollectionView faktycznie renderuje.
Womble,
1

Wersja Swift 3

Po prostu utwórz podklasę UICollectionViewFlowLayout i wklej tę metodę.

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
źródło
Działa to w przypadku dopasowania poziomego, ale odstępy między wierszami pozostaną, nawet jeśli parametr minimumLineSpacingForSectionAt ma wartość 0, a layout.minimumLineSpacing jest ustawiony na 0. Ponadto dotknięcie w kolekcjiView spowoduje awarię aplikacji z powodu braku pierwszej pętli zakresu.
Womble,
1

Próbowałem odpowiedzi iago849 i zadziałało.

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

Oto link do projektu github. https://github.com/vishalwaka/MultiTags

vishalwaka
źródło
0

Poprzednie wersje tak naprawdę nie działały z sekcjami> 1. Więc moje rozwiązanie zostało znalezione tutaj https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ . Dla leniwych:

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
źródło
0

Mam problem z zaakceptowaną odpowiedzią, więc zaktualizowałem ją, działa dla mnie:

.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
źródło
0

Moje rozwiązanie w zakresie Swift 3odstępów między liniami komórkowymi jak na Instagramie:

wprowadź opis zdjęcia tutaj

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

Jak programowo wykryć urządzenie: https://stackoverflow.com/a/26962452/6013170

Zhanserik
źródło
0

Cóż, jeśli tworzysz poziomy widok kolekcji, aby zwolnić miejsce między komórkami, musisz ustawić właściwość minimumLineSpacing.

Shanu Singh
źródło
-1

Spróbuj pobawić się tą metodą:

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

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

    return insets;
}
Nikola Kirev
źródło
2
Działa to tylko w przypadku odstępów między sekcjami, a nie komórek
Diego A. Rincon,