Espacio entre celdas en UICollectionView

197

¿Cómo configuro el espacio entre celdas en una sección de UICollectionView? Sé que hay una propiedad minimumInteritemSpacingque la configuré en 5.0, pero el espaciado no aparece en 5.0. He implementado el método de delegado de flujo.

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

    return 5.0;
}

Todavía no estoy obteniendo el resultado deseado. Creo que es el espacio mínimo. ¿No hay alguna manera de establecer el espacio máximo?

simulador sc

Vishal Singh
fuente
¿comprobaste si está entrando en el método delegado o no ...? poniendo el punto de quiebre ..
Prashant Nikam
sí, está ingresando al delegado, en IB también he establecido el espacio mínimo de celdas en 5. Pero no creo que el espacio mínimo sea la propiedad que me ayudará, ya que solo se asegurará de que el espacio mínimo entre celdas sea de 5, pero si la vista de colección tiene espacio extra, entonces usará ese espacio extra. Debería haber algo como el máximo espacio entre celdas
Vishal Singh
Tengo el mismo problema. 5px parece no funcionar. Interesantemente puedo hacer esto con un UITableView, pero no con un UICollectionView ...
jerik
Lo arreglé haciendo algunos cálculos ... lo publicaré mañana. :)
Vishal Singh
NOTA PARA 2016 es así de fácil: stackoverflow.com/a/28327193/294884
Fattie

Respuestas:

145

Sé que el tema es antiguo, pero en caso de que alguien todavía necesite una respuesta correcta, aquí lo que necesita:

  1. Anular el diseño de flujo estándar.
  2. Agregue implementación como esa:

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

donde maximumSpacing se puede establecer en cualquier valor que prefiera. ¡Este truco garantiza que el espacio entre las celdas sea EXACTAMENTE igual al espaciamiento máximo!

iago849
fuente
Entonces, ¿dónde ponemos esto?
Jonny
1
Hola Jonny, hereda de Flow Layout estándar y solo copia y pega este método en tu clase.
iago849
1
Tenga en cuenta que no necesita hacer un mutableCopy: no está mutando el contenido de la matriz, sino mutando los objetos dentro de ella.
Brock Boland
55
tal vez hago algo mal o esta idea no funciona al 100%, porque cuando me desplazo hasta el final veo que algunas celdas se superponen entre sí :(
pash3r
2
Buena publicación. Encontré un error al alterar el formato de la última línea del diseño en algunas circunstancias. Para resolver, cambié ifa Y una condición adicional: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota
190

Apoyando la pregunta inicial. Traté de obtener el espacio a 5px en el UICollectionViewpero esto no funciona, así que con un UIEdgeInsetsMake(0,0,0,0)...

En un UITableView puedo hacer esto especificando directamente las coordenadas x, y en una fila ...

ingrese la descripción de la imagen aquí

Aquí está mi código 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;
}

Actualización: resolvió mi problema con el siguiente código.

ingrese la descripción de la imagen aquí

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
fuente
Esta es una respuesta mucho mejor. Eche un vistazo a las devoluciones de llamada que puede ajustar en UICollectionViewDelegateFlowLayout y puede ver cómo se puede ajustar esto.
cynistersix
1
Creo que esto solo puede funcionar cuando el ancho del elemento + espaciado es igual al ancho de uicollectionview.
xi.lin
@JayprakashDubey actualmente no estoy en forma rápida. Tienes que intentarlo. Buena suerte
jerik
¿Dónde especificas el ancho entre las celdas de 5px?
UKDataGeek
1
Respuesta mucho mejor que la aceptada, principalmente porque subclasificar UICollectionViewLayout solo para anular un método parece una exageración, y no es una cuestión trivial dados todos los demás métodos que deben anularse.
Cindeselia
80

Usando un diseño de flujo horizontal, también estaba obteniendo un espacio de 10 puntos entre las celdas. Para eliminar el espaciado, necesitaba establecer minimumLineSpacingasí como minimumInterItemSpacingcero.

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

Además, si todas sus celdas son del mismo tamaño, es más simple y más eficiente establecer la propiedad en el diseño del flujo directamente en lugar de utilizar métodos delegados.

Jason Moore
fuente
34
Sorprendentemente, minimalLineSpacing afecta el espacio horizontal entre celdas.
Matt H
44
Yo también, necesito un desplazamiento horizontal y espacio cero entre celdas, y mínimoLineSpacing = 0 es la clave.
Wingzero
3
Pude obtener este efecto sin usar minimumInteritemSpacing. Solo establecer minimumLineSpacing = 0mi diseño horizontal eliminó el espacio horizontal entre los elementos.
Ziewvater
1
Si lo piensa, la distancia horizontal entre los elementos ES el espacio entre líneas para un diseño que fluye horizontalmente. El espacio entre líneas es la distancia vertical entre elementos en un diseño típico que fluye verticalmente.
lancejabr
62

Recuerde, es el espacio mínimo de línea , no el espacio mínimo entre elementos o el espacio celular. Porque la dirección de desplazamiento de su collectionView es HORIZONTAL .

Si es vertical, debe establecer el espacio de celda o el espacio entre elementos para el espacio horizontal entre celdas y el espacio entre líneas para el espacio vertical entre celdas.

Versión Objective-C

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

Versión rápida:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 20
}
Vincent Joy
fuente
ahora el espacio inferior se ha ido cuando devuelvo 0; ¿Cómo eliminar el espacio lateral derecho?
Bangalore
Oye, no entendí tu pregunta muy bien. Pero creo que insetForSectionAtIndex es lo que estás buscando. - (UIEdgeInsets) collectionView: (UICollectionView *) collectionView layout: (UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex: (NSInteger) section {return UIEdgeInsetsMake (5, 10, 5, 10); }
Vincent Joy
Es un espacio mínimo entre líneas tanto horizontal como vertical.
Swati
Me salvaste el día (Y).
Umair_UAS
¡Oh mi palabra! No puedo creer esto. Gracias
Magoo
36

Pruebe este código para asegurarse de tener un espacio de 5 píxeles entre cada elemento:

- (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
fuente
Formatee su código como un bloque de código para que se vea bien en SO.
Conducto
33

Versión rápida de la respuesta más popular. El espacio entre las celdas será igual a 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
fuente
super.layoutAttributesForElements (en: rect) está devolviendo nil alguna idea?
Ashok R
Al igual que todos los otros métodos que usan esto, esto no funciona correctamente para varias filas. Los espacios intermitentes de estilo de error de redondeo permanecerán entre las filas, incluso con los métodos y propiedades de delegado apropiados configurados para usar 0. Puede ser un problema de representación de UICollectionView.
Womble
30

He encontrado una manera muy fácil de configurar el espaciado entre celdas o filas utilizando IB.

Simplemente seleccione UICollectionView del archivo storyboard / Xib y haga clic en Size Inspector como se especifica en la imagen a continuación.

ingrese la descripción de la imagen aquí

Para configurar el espacio mediante programación, use las siguientes propiedades.

1) Para configurar el espacio entre filas.

[self.collectionView setMinimumLineSpacing:5];

2) Para configurar el espacio entre elementos / celdas.

[self.collectionView setMinimumInteritemSpacing:5];
Aamir
fuente
1
Ese es el espacio mínimo, que será mayor que el valor especificado y no siempre el valor especificado.
Vishal Singh
21

Tenga en cuenta el nombre de la propiedad minimalInterItemSpacing . Este será el espacio mínimo entre los elementos, no el espacio exacto . Si establece el valor minimalInterItemSpacing en algún valor, puede asegurarse de que el espaciado no sea menor. Pero existe la posibilidad de obtener un valor más alto.

En realidad, el espacio entre los elementos depende de varios factores itemSize y sectionInset . La vista de colección coloca dinámicamente los contenidos en función de estos valores. Por lo tanto, no puede asegurar el espacio exacto. Debería realizar alguna prueba y error con sectionInset y minimumInterItemSpacing .

Anil Varghese
fuente
1
@Anil insectos de borde? : D
NightFury
10
Puede haber errores en su sección.
Néstor
24
insecto == error && insecto! = recuadro :)
Nestor
16

Respuesta para Swift 3.0, Xcode 8

1.Asegúrese de configurar el delegado de vista de colección

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

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

2.Implemente el protocolo UICollectionViewDelegateFlowLayout , no 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
fuente
1
Piensa que puedes eliminar al público allí. Debería funcionar bien y ser coherente con todas las demás funciones.
Edward Potter
¿Funcionaría esto para la vista de colección de desplazamiento vertical? Tengo una vista de colección en la que debería mostrar 2 celdas horizontalmente en dispositivos como iPhone 6s y 6s Plus, pero debería mostrar solo una celda para algo inferior a eso, es decir, 5s, 5 y SE. Mi código actual está funcionando, pero en el dispositivo 6s Plus el espacio entre las celdas es demasiado y se ve feo y estoy tratando de reducir ese espacio y ese es el único requisito ya que todos los demás dispositivos funcionan según mi diseño.
AnBisw
11

Código simple para espaciado

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value
AMayes
fuente
3
Para el espaciado horizontal de celdas se debe usar: minimumLineSpacing
Alfi
9

La respuesta votada (y también la versión rápida ) tiene un pequeño problema: habrá un gran espacio a la derecha.

Esto se debe a que el diseño del flujo se personaliza para hacer que el espacio entre celdas sea exacto, con un comportamiento flotante a la izquierda .

Mi solución es manipular el recuadro de la sección, de modo que la sección esté alineada en el centro, pero el espaciado es exactamente como se especifica.

En la captura de pantalla a continuación, el espacio entre elementos y líneas es exactamente de 8 puntos, mientras que la sección de inserción izquierda y derecha será mayor de 8 puntos (para que quede alineada en el centro):

celdas espaciadas uniformemente

Código rápido como tal:

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
fuente
1
Recibo una 'NSInvalidArgumentException', razón: '*** setObjectForKey: el objeto no puede ser nulo (clave: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0})' excepción no detectada.
DaftWooly
... si no me equivoco, su ciclo while es equivalente a: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly
No usé el código tal como está, pero esto me dio la mejor referencia para implementar mi diseño de flujo de salida para la vista de colección. aplausos
Dima Gimburg 05 de
8

Defina el UICollectionViewDelegateFlowLayoutprotocolo en su archivo de encabezado.

Implemente el siguiente método de UICollectionViewDelegateFlowLayoutprotocolo como este:

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

Haga clic aquí para ver la documentación del UIEdgeInsetMakemétodo de Apple .

Salman Zaidi
fuente
4

Enfoque del guión gráfico

Seleccione CollectionView en su guión gráfico y vaya al inspector de tamaño y configure el espaciado mínimo para celdas y líneas como 5

Swift 5 programáticamente

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
fuente
3

Si desea ajustar el espacio sin tocar el tamaño real de la celda, esta es la solución que mejor funcionó para mí. #xcode 9 # tvOS11 # iOS11 #swift

Entonces, en UICollectionViewDelegateFlowLayout , cambiar implementar los siguientes métodos, el truco es que tienes que usar ambos, y la documentación realmente no me indicaba que pensara en esa dirección. :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
fuente
2

Estoy usando monotouch, por lo que los nombres y el código serán un poco diferentes, pero puede hacerlo asegurándose de que el ancho de la vista de colección sea igual a (x * ancho de celda) + (x-1) * espaciado mínimo con x = cantidad de celdas por fila.

Simplemente siga los pasos basados ​​en su espaciado mínimo de elemento y el ancho de la celda

1) Calculamos la cantidad de elementos por fila en función del tamaño de celda + insertos actuales + espaciado mínimo

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

2) Ahora tiene toda la información para calcular el ancho esperado para la vista de colección

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

3) Entonces, la diferencia entre el ancho actual y el ancho esperado es

float difference = currentTotalWidth - totalWidth;

4) Ahora ajuste las inserciones (en este ejemplo lo agregamos a la derecha, para que la posición izquierda de la vista de colección permanezca igual)

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;
Mate
fuente
2

Tengo una horizontal UICollectionViewy subclase UICollectionViewFlowLayout. La vista de colección tiene celdas grandes, y solo muestra una fila de ellas a la vez, y la vista de colección se ajusta al ancho de la pantalla.

Intenté la respuesta de iago849 y funcionó, pero luego descubrí que ni siquiera necesitaba su respuesta. Por alguna razón, configurar el minimumInterItemSpacingno hace nada. El espacio entre mis elementos / celdas se puede controlar por completo minimumLineSpacing.

No estoy seguro de por qué funciona de esta manera, pero funciona.

usuario3344977
fuente
1
esto parece ser cierto , curiosamente el valor de "líneas" es, de hecho, el separador entre elementos en el caso de un diseño horizontal.
Fattie
Hola @ user3344977 - bonito hallazgo. Decidí separar este problema en una pregunta separada que aborda directamente las vistas de colección de desplazamiento horizontal para que sea más fácil de encontrar para algunas personas. Me refiero a su respuesta allí. Mi pregunta está aquí: stackoverflow.com/q/61774415/826946
Andy Weinstein
1

Me topé con un problema similar al OP. Lamentablemente, la respuesta aceptada no funcionó para mí, ya que el contenido de la collectionViewno se centraría correctamente. Por lo tanto, se me ocurrió una solución diferente que solo requiere que todos los elementos en el collectionViewson del mismo ancho , que parece ser el caso en la pregunta:

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

Ese código garantizará que el valor devuelto por ...minimumInteritemSpacing...sea ​​el espacio exacto entre todos collectionViewCelly además garantizará que las celdas se centren en elcollectionView

luk2302
fuente
Eso es muy bonito. Pero me preguntaba si se podría aplicar una solución similar al espaciado vertical entre elementos
p0lAris
Espaciado vertical en caso de que tenga desplazamiento horizontal?
luk2302
1

La solución anterior de vojtech-vrbka es correcta pero activa una advertencia:

advertencia: UICollectionViewFlowLayout tiene una falta de coincidencia de trama en caché para la ruta del índice - valor en caché: Esto es probable que ocurra porque la subclase de diseño de flujo Diseño modifica atributos devueltos por UICollectionViewFlowLayout sin copiarlos

El siguiente código debería solucionarlo:

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
fuente
2
Al igual que las otras respuestas en SO que usan este enfoque, esto funciona para ajustar celdas en todo el ancho de collectionView, pero los espacios intermitentes de altura variable aún permanecen entre las filas. Esto puede ser una limitación de la forma en que CollectionView realmente representa.
Womble
1

Versión Swift 3

Simplemente cree una subclase UICollectionViewFlowLayout y pegue este método.

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
fuente
Esto funciona para el ajuste horizontal, pero los huecos permanecerán entre las filas, incluso si mínimoLineSpacingForSectionAt está configurado para devolver 0, y layout.minimumLineSpacing está establecido en 0. Además, un toque en collectionView bloqueará la aplicación, debido a que el primer bucle está fuera de rango.
Womble
1

He intentado la respuesta de iago849 y funcionó.

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
}

Aquí está el enlace para el proyecto github. https://github.com/vishalwaka/MultiTags

vishalwaka
fuente
0

Las versiones anteriores realmente no funcionaban con las secciones> 1. Así que mi solución se encontró aquí https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/ . Para los flojos:

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
fuente
0

Tengo un problema con la respuesta aceptada, así que la actualicé, esto funciona para mí:

.h

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

.metro

@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
fuente
0

Mi solución en Swift 3el espaciado de líneas celulares como en Instagram:

ingrese la descripción de la imagen aquí

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

Cómo detectar el dispositivo mediante programación: https://stackoverflow.com/a/26962452/6013170

Zhanserik
fuente
0

Bueno, si está creando una vista de colección horizontal para dar espacio entre las celdas, debe establecer la propiedad minimumLineSpacing.

Shanu Singh
fuente
-1

Intenta jugar con este método:

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

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

    return insets;
}
Nikola Kirev
fuente
2
Esto solo funciona para el espacio entre secciones, no celdas
Diego A. Rincón