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


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!


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

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.


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
}

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

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

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];

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 .


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

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

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
}

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.


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
}

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

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;

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.


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


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

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
}

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


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
}

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

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


0

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


-1

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

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

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

    return insets;
}

2
Działa to tylko w przypadku odstępów między sekcjami, a nie komórek
Diego A. Rincon,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.