ios - rotacion - UICollectionViewFlowLayout Size Warning al girar el dispositivo hacia el paisaje
rotar pantalla iphone 6 (21)
Acabo de encontrar y solucionó el mismo problema. Como mi solución es más parecida a la que estaba solicitando y no coincide con ninguna respuesta existente, la publiqué aquí.
#define NUMBER_OF_CELLS_PER_ROW 1
- (UICollectionViewFlowLayout *)flowLayout {
return (UICollectionViewFlowLayout *)self.collectionViewLayout;
}
- (CGSize)itemSizeInCurrentOrientation {
CGFloat windowWidth = self.collectionView.window.bounds.size.width;
CGFloat width = (windowWidth - (self.flowLayout.minimumInteritemSpacing * (NUMBER_OF_CELLS_PER_ROW - 1)) - self.flowLayout.sectionInset.left - self.flowLayout.sectionInset.right)/NUMBER_OF_CELLS_PER_ROW;
CGFloat height = 80.0f;
return CGSizeMake(width, height);
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.flowLayout invalidateLayout];
self.flowLayout.itemSize = [self itemSizeInCurrentOrientation];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
// Now that the rotation is complete, load the cells.
[self.collectionView reloadData];
}
Estamos utilizando un UICollectionView para mostrar la celda que cubre la pantalla completa (menos el estado y la barra de navegación). El tamaño de la celda se establece desde self.collectionView.bounds.size
:
- (void)viewWillAppear:(BOOL)animated
{
//
// value isn''t correct with the top bars until here
//
CGSize tmpSize = self.collectionView.bounds.size;
_currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return _currentCellSize;
}
Esto establece el tamaño correcto para cada dispositivo. Cada celda está definida para no tener inserciones, y el diseño no tiene encabezado o pie de página. Sin embargo, cuando giramos de vertical a horizontal obtenemos la siguiente "queja":
the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less that the height of the UICollectionView minus the section insets top and bottom values.
Ahora entiendo este error, sin embargo, restablecemos el tamaño de la celda y usamos los diseños de flujo integrados en la transición de rotación:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//self.collectionView.bounds are still the last size...not the new size here
}
- (void)didRotateFromInterfaceOrientation: UIInterfaceOrientation)fromInterfaceOrientation
{
CGSize tmpSize = self.collectionView.bounds.size;
_currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
[self.collectionView performBatchUpdates:nil completion:nil];//this will force the redraw/size of the cells.
}
Las celdas se representan correctamente en el paisaje.
Parece que Flow Layout ve el tamaño de celda anterior (lo que provoca la queja ya que será demasiado alto), pero lee / representa el nuevo tamaño de celda establecido en didRotateFromInterfaceOrientation
.
¿Hay alguna manera de deshacerse de la queja?
Hemos intentado encontrar otro gancho durante una transición de rotación del dispositivo que tiene acceso al tamaño correcto de la pantalla objetivo (frente al tamaño de pantalla actual) sin suerte. La salida de depuración muestra que la queja ocurre después de que willRotateToInterfaceOrientation
pero antes didRotateFromInterfaceOrientation
.
También hemos verificado lo obvio; si configuramos la altura de la celda para que sea de un tamaño fijo inferior a la altura de la pantalla de paisaje, la queja no se produce. Además, la queja no se produce al girar desde el paisaje de vuelta a retrato.
Todo funciona bien y se procesa correctamente. Sin embargo, esta queja nos preocupa. ¿Alguien más tiene alguna idea o solución?
El siguiente código me lo arregló:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}
En
[UIViewController willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration]
Llamé al, [UICollectionViewLayout invalidateLayout]
y parece funcionar bien.
Estaba recibiendo la misma advertencia. Insatisfecho con el enfoque "reloadData", descubrí que al llamar [self.collectionView.collectionViewFlowLayout invalidateLayout]
antes de establecer el marco de la vista de colección se silenció la advertencia y se obtuvieron los resultados esperados.
Esto funciona para mí: (¡y espero que también funcione para ti!)
- (void)viewWillLayoutSubviews
{
self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height);
[self.flowLayout invalidateLayout];
}
- (void)viewDidLayoutSubviews
{
self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height);
}
Esto lo resolvió para mí:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.collectionView.collectionViewLayout invalidateLayout];
}
Y estoy usando este método de delegado para configurar el tamaño:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
Y desde allí puedo usar esto con el marco correcto después de la rotación:
self.collectionView.frame.size
He usado un UICollectionViewFlowLayoutInvalidationContext
, en el que calculo el nuevo desplazamiento de manera que mantenga el mismo offset de contenido. Mi propia collectionViewSizeForOrientation:
funciones collectionViewSizeForOrientation:
devuelve el tamaño adecuado. No es perfecto, pero al menos no es incompleto:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
CGSize fromCollectionViewSize = [self collectionViewSizeForOrientation:[self interfaceOrientation]];
CGSize toCollectionViewSize = [self collectionViewSizeForOrientation:toInterfaceOrientation];
CGFloat currentPage = [_collectionView contentOffset].x / [_collectionView bounds].size.width;
NSInteger itemCount = [_collectionView numberOfItemsInSection:0];
UICollectionViewFlowLayoutInvalidationContext *invalidationContext = [[UICollectionViewFlowLayoutInvalidationContext alloc] init];
[invalidationContext setContentSizeAdjustment:CGSizeMake(toCollectionViewSize.width * itemCount - fromCollectionViewSize.width * itemCount, toCollectionViewSize.height - fromCollectionViewSize.height)];
[invalidationContext setContentOffsetAdjustment:CGPointMake(currentPage * toCollectionViewSize.width - [_collectionView contentOffset].x, 0)];
[[_collectionView collectionViewLayout] invalidateLayoutWithContext:invalidationContext];
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
collectionViewSizeForOrientation:
en mi caso es el siguiente, suponiendo que las inserciones y el espaciado entre elementos son 0:
- (CGSize)collectionViewSizeForOrientation:(UIInterfaceOrientation)orientation
{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGFloat width = UIInterfaceOrientationIsLandscape(orientation) ? MAX(screenSize.width, screenSize.height) : MIN(screenSize.width, screenSize.height);
CGFloat height = UIInterfaceOrientationIsLandscape(orientation) ? MIN(screenSize.width, screenSize.height) : MAX(screenSize.width, screenSize.height);
return CGSizeMake(width, height);
}
Lo solucioné
Debería dejar que la altura del flujo sea inferior a collcetionView.frame.size.height.
[flowLayout setItemSize:CGSizeMake(width, height)];
collectionView.frame = CGRectMake(12, 380, 290, 80);
Me encontré con el mismo problema al cambiar el tamaño del marco de un UICollectionView. Si utilicé el método de delegado en FlowLayout para devolver el tamaño de la celda (que se actualizaría en función del tamaño de UICollectionView que lo contiene), obtendría el mensaje de error cuando redimensione (más pequeño) el marco de UICollectionView, ya que no pareció pedirle al delegado información actualizada sobre el tamaño antes de quejarse. Eventualmente le pediría al método de delegado la información del tamaño al volver a dibujar, pero aún emitiría la advertencia en el momento en que asigné un nuevo método de marco. Para deshacerme de la advertencia, establecí explícitamente la propiedad itemSize del objeto UICollectionViewFlowLayout antes de establecer el marco en un nuevo valor más pequeño. Mi situación es tan simple que creo que puedo salir adelante haciendo el cálculo de itemSize en este punto (ya que todos mis artículos en la vista de colección son del mismo tamaño), en lugar de depender del método de delegado. El solo hecho de configurar la propiedad itemSize dejando el método delegado implementado no resolvió el problema, ya que creo que ignoró el valor de itemSize si detectó que se implementó el método delegado (si sabe que está allí, por qué no lo llama) ?!). Esperemos que esto ayude, quizás también pueda establecer explícitamente el itemSize antes de la rotación.
Me encontré con este mismo problema. Si la vista de la colección se muestra cuando está en orientación vertical, las celdas desaparecerán al rotar al paisaje. Hice una combinación de las otras respuestas aquí para arreglar esto.
Configuro mi vista (la que contiene UICollectionView) para recibir la notificación UIDeviceOrientationDidChangeNotification
. En el método que responde a esa notificación, después de ajustar el marco UICollectionView, hice lo siguiente:
- (void)orientationChanged:(NSNotification *)notification
{
CGSize size = (CGSize){self.frame.size.width - 2*kContentMargin, self.frame.size.height - 2*kContentMargin};
[self.collectionView.collectionViewLayout setItemSize:size];
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView reloadData];
}
Tenga en cuenta que el marco de UICollectionView se establece automáticamente en la rotación porque su resizingMask está configurado a esto al momento de la inicialización:
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Me enfrenté al mismo problema. así es como lo resolví. Espero eso ayude
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:( NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.collectionView reloadData];
}
Mi solución fue tan simple como desactivar la opción ''Ajustar las configuraciones de la vista de desplazamiento'' para el controlador de vista en IB, ya que necesitaba que mi barra de navegación fuera translúcida.
Muchas de las soluciones sugieren agregar invalidateLayout
a willAnimateRotationToInterfaceOrientation
, pero esto está obsoleto desde iOS 8.
Para iOS 8 y superior, use:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self.collectionView.collectionViewLayout invalidateLayout];
}
Gracias al comentario de @ user7097242 aquí está una versión swift4:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
self.collectionView.collectionViewLayout.invalidateLayout()
}
No arrojar otro camarón en esta barbie cargada, pero no aceptada.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
[collectionView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
return CGSizeMake(100, collectionView.frame.size.height);
}
Configurar las inserciones de contenido justo antes de devolver el tamaño de la celda me sirvió de algo.
Nota:
Estoy usando una vista de contenedor en un guión gráfico para cargar la vista de colección dentro de un UIViewController. Intenté configurar esto en el objeto flowLayout en el guión gráfico. La vista de colección en el guión gráfico. Y anulando uno de UICollectionViewDelegateFlowLayout; aunque no recuerdo cuál. Tampoco estoy seguro si esto funcionará para un diseño vertical.
Nota: en mi caso, descubrí que estábamos configurando la propiedad de UIViewController
preferredContentSize
de UIViewController
en cuestión. Si considera que este es su caso, es posible que tenga que tratar con el siguiente método del protocolo UICollectionViewDelegateFlowLayout
:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = collectionViewLayout.collectionView.bounds.size;
...
return size;
}
Prueba esto...
UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;
layout.itemSize = CGSizeMake(0.1, 0.1);
Es un trabajo para mi
Puede subclase UICollectionView
y anular setBounds:
Antes de llamar a [super setBounds:]
el tamaño del elemento se puede ajustar a los nuevos límites.
Debería verificar si el tamaño de los límites ha cambiado, porque setBounds:
también se invoca al desplazarse.
Sé que esta es una vieja pregunta, pero acabo de tener el mismo problema y pasé una hora para resolverlo. Mi problema es que, parece que el tamaño de fotograma de UICollectionView siempre es incorrecto (la altura no coincide con el contenedor) mientras configuro el tamaño de fotograma justo antes de que se llame al delegado de diseño de UICollectionView Flow. Entonces, configuré el tamaño del marco UICollectionView nuevamente en el método:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
Y ese fue el truco. La altura ahora se muestra correctamente y la advertencia se ha ido.
Solo para suprimir la advertencia y (probablemente, no estoy seguro) mejorar el rendimiento que podría antes de devolver el tamaño en
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
compruebe si el controlador de vista está en proceso de rotación y si devuelve un tamaño relativamente pequeño como CGSizeMake(0.1, 0.1)
Tratar de encontrar una solución para silenciar estas advertencias en iOS 7 me resultó difícil. Terminé recurriendo a la subclasificación de mi UICollectionView
y agregué el siguiente código.
- (void)setFrame:(CGRect)frame
{
if (!iOS8 && (frame.size.width != self.frame.size.width))
{
[self.collectionViewLayout invalidateLayout];
}
[super setFrame:frame];
}
Algunos pueden querer hacer una verificación de tamaño completo con CGSizeEqualToSize()
.
intente al final de didRotateFromInterfaceOrientation:
[self.collectionView setNeedsLayout]
si no funciona intente mover todo esto de didRotateFromInterfaceOrientation a willRotateToInterfaceOrientation