ios - UICollectionView-desplazamiento horizontal, diseño horizontal?
layout uicollectionviewlayout (11)
Tengo un UIScrollView que establece una grilla de iconos. Si imaginas el diseño de iOS Springboard, estarías muy cerca de corregirlo. Tiene un desplazamiento horizontal, paginado (como Springboard). Sin embargo, parece que el diseño no es del todo correcto. Parece como si estuviera diseñando los elementos de arriba a abajo. Como resultado, mi última columna solo tiene 2 filas, debido a la cantidad de elementos que se mostrarán. Prefiero que mi última fila en la última página tenga 2 elementos, como los que verá en el trampolín.
¿Cómo se puede lograr esto con UICollectionView y sus clases relacionadas? ¿Debo escribir un UICollectionViewFlowLayout personalizado?
Primer acercamiento
¿Qué hay de usar UIPageViewController
con una matriz de UICollectionViewControllers
? Tendría que buscar la cantidad adecuada de elementos en cada UICollectionViewController
, pero no debería ser difícil. Tendrás exactamente el mismo aspecto que tiene Springboard.
Segundo enfoque
He pensado sobre esto y en mi opinión tienes que establecer:
self.collectionView.pagingEnabled = YES;
y crea tu propio diseño de vista de colección subclasificando UICollectionViewLayout
. Desde el objeto de diseño personalizado, puede acceder a self.collectionView
, para que sepa cuál es el tamaño del frame
la vista de colección, numberOfSections
y numberOfItemsInSection:
Con esa información puede calcular los frames
las celdas (en prepareLayout
) y collectionViewContentSize
. Aquí hay algunos artículos sobre cómo crear diseños personalizados:
- https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCustomLayouts/CreatingCustomLayouts.html
- http://www.objc.io/issue-3/collection-view-layouts.html
3º enfoque
Puede hacer esto (o una aproximación) sin crear el diseño personalizado. Agregue UIScrollView
en la vista en blanco, configure la paginación habilitada en ella. En la vista de desplazamiento, agregue una vista de colección. A continuación, agregue una restricción de ancho, verifique en el código cuántos elementos tiene y establezca su constant
en el valor correcto, por ejemplo (self.view.frame.size.width * numOfScreens)
. Así es como se ve (los números en las celdas muestran el indexPath.row
): https://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.mov Si no está satisfecho con la forma en que se ordenan las celdas, entonces tengo miedo tendrías que ir con 1. o 2.
¿Has intentado configurar la dirección de desplazamiento de tu UICollectionViewFlowLayout en horizontal?
[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
Y si desea que la página se muestre como lo hace el trampolín, deberá habilitar la búsqueda en su vista de colección de la siguiente manera:
[yourCollectionView setPagingEnabled:YES];
De @Erik Hunter, publico el código completo para hacer UICollectionView
horizontal
UICollectionViewFlowLayout *collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[collectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.myCollectionView.collectionViewLayout = collectionViewFlowLayout;
En Swift
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
self.myCollectionView.collectionViewLayout = layout
En Swift 3.0
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.myCollectionView.collectionViewLayout = layout
Espero que esto ayude
Este código funciona bien en Swift 3.1 y Xcode 8.3.2
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.collectionView.collectionViewLayout = layout
self.collectionView!.contentInset = UIEdgeInsets(top: -10, left: 0, bottom:0, right: 0)
if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.itemSize = CGSize(width: self.view.frame.size.width-40, height: self.collectionView.frame.size.height-10)
layout.invalidateLayout()
}
}
Estoy trabajando en Xcode 6.2 y para el desplazamiento horizontal he cambiado la dirección de desplazamiento en el inspector de atributos.
haga clic en collectionView-> attribute inspector-> scroll Direction-> change to horizontal
Espero que esto ayude a alguien.
Podemos hacer el mismo comportamiento de Springboard usando UICollectionView y para eso tenemos que escribir código para el diseño personalizado.
Lo logré con la implementación personalizada de la clase de diseño con "SMCollectionViewFillLayout"
Repositorio de código:
https://github.com/smindia1988/SMCollectionViewFillLayout
Salida como abajo:
1.png
2_Code_H-Scroll_V-Fill.png
Puede escribir un diseño UICollectionView
personalizado para lograr esto, aquí está la imagen de demostración de mi implementación:
Aquí está el repositorio de código: KSTCollectionViewPageHorizontalLayout
@iPhoneDev (esto quizás también te ayude)
Si define UICollectionViewFlowLayout
en el código, anulará las configuraciones de Interface Builder. Por lo tanto, necesita volver a definir la scrollDirection
nuevamente.
let layout = UICollectionViewFlowLayout()
...
layout.scrollDirection = .Horizontal
self.awesomeCollectionView.collectionViewLayout = layout
Solo por diversión, otro enfoque sería simplemente dejar el juego de paginación y desplazamiento horizontal, agregar un método que cambie el orden de los elementos de la matriz para convertir de ''arriba a abajo, de izquierda a derecha'' a visualmente ''de izquierda a derecha, de arriba a abajo ''y llene las celdas intermedias con celdas ocultas vacías para hacer el espaciado correcto. En el caso de 7 elementos en una grilla de 9, esto sería así:
[1][4][7]
[2][5][ ]
[3][6][ ]
debe convertirse
[1][2][3]
[4][5][6]
[7][ ][ ]
entonces 1 = 1, 2 = 4, 3 = 7 etc. y 6 = vacío. Puede reordenarlos calculando el número total de filas y columnas, luego calcula el número de fila y columna para cada celda, cambia la fila para la columna y viceversa y luego tienes los nuevos índices. Cuando la celda no tiene un valor correspondiente a la imagen, puede devolver una celda vacía y establecer cell.hidden = YES;
lo.
Funciona bastante bien en una aplicación de caja de resonancia que construí, así que si alguien quisiera trabajar en el código, lo agregaré. Solo se requiere un pequeño código para hacer que este truco funcione, ¡suena más difícil de lo que es!
Actualizar
Dudo que esta sea la mejor solución, pero a pedido aquí está el código de trabajo:
- (void)viewDidLoad {
// Fill an `NSArray` with items in normal order
items = [NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:@"Some label 1", @"label", @"Some value 1", @"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Some label 2", @"label", @"Some value 2", @"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Some label 3", @"label", @"Some value 3", @"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Some label 4", @"label", @"Some value 4", @"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Some label 5", @"label", @"Some value 5", @"value", nil],
nil
];
// Calculate number of rows and columns based on width and height of the `UICollectionView` and individual cells (you might have to add margins to the equation based on your setup!)
CGFloat w = myCollectionView.frame.size.width;
CGFloat h = myCollectionView.frame.size.height;
rows = floor(h / cellHeight);
columns = floor(w / cellWidth);
}
// Calculate number of sections
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return ceil((float)items.count / (float)(rows * columns));
}
// Every section has to have every cell filled, as we need to add empty cells as well to correct the spacing
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return rows*columns;
}
// And now the most important one
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier@"myIdentifier" forIndexPath:indexPath];
// Convert rows and columns
int row = indexPath.row % rows;
int col = floor(indexPath.row / rows);
// Calculate the new index in the `NSArray`
int newIndex = ((int)indexPath.section * rows * columns) + col + row * columns;
// If the newIndex is within the range of the items array we show the cell, if not we hide it
if(newIndex < items.count) {
NSDictionary *item = [items objectAtIndex:newIndex];
cell.label.text = [item objectForKey:@"label"];
cell.hidden = NO;
} else {
cell.hidden = YES;
}
return cell;
}
Si desea utilizar el método didSelectItemAtIndexPath
, debe usar la misma conversión que se utiliza en cellForItemAtIndexPath
para obtener el elemento correspondiente. Si tiene márgenes de celda, debe agregarlos al cálculo de filas y columnas, ya que deben ser correctos para que esto funcione.
UICollectionView
reducir la altura de UICollectionView
a la altura de su celda / elemento y seleccionar " Horizontal
" desde la " Scroll Direction
" como se ve en la captura de pantalla siguiente. Luego se desplazará horizontalmente según el número de elementos que haya devuelto en la implementación de su fuente de datos.