Un error UICollectionView con una altura dinámica
Dado que he estado luchando durante 3 días con este problema y ya lo he preguntado dos veces, pero tal vez no estaba claro, decidí investigar el problema y encontré un comportamiento defectuoso con esta vista.
Mostraré todo el código simple, para que cualquiera pueda reproducir el error (iPad Air).
Estoy estableciendo uncollectionView
flowlayout que subclasifica el diseño para obtener un espacio constante entre las celdas, y aquí está el comienzo:
TopAlignedCollectionViewFlowLayout *layout = [[TopAlignedCollectionViewFlowLayout alloc] init];
CGRect size = CGRectMake(0, 0, 900, 1200);
self.GridView = [[UICollectionView alloc] initWithFrame:size
collectionViewLayout:layout];
[self.GridView registerClass:[GridCell class] forCellWithReuseIdentifier:@"Cell"];
[self.GridView setDelegate:self];
[self.GridView setDataSource:self];
[self.view addSubview:self.GridView];
Entonces configurar mis delegados es tan simple como eso: (la altura es dinámica )
#pragma grid- main functions
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 80;
}
//cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout
, sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
{
//a random dynamic height of a cell
int a = arc4random()%300;
CGSize size = CGSizeMake( 340, 240+a );
return size;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=@"Cell";
GridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:@"%d",indexPath.row];
NSLog(@"%d",indexPath.row);
return cell;
}
Ahora la subclase, para obtener un espaciado constante: (TopAlignedCollectionViewFlowLayout
)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
#define numColumns 2
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns) {
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns
inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
Cualquiera puede verificar y ver que después de desplazarse por un momento, obtiene un extraño efecto de espacios en blanco que se llenan últimamente por sus celdas, algo así como:
1 2
3 4
6
8
NOTA: 5-7 se cargan más tarde.
EDITAR1:
Al eliminar la altura aleatoria del método de delegado de tamaño de celda, establecerla en altura constante, resuelve este problema.
El problema es: la altura de la celda debe ser dinámica.
EDIT2: Establecer la altura aleatoria (int a) para que sea menor, también hace que el problema desaparezca, (<100), significa que cuanto menor sea la altura de la distancia entre las celdas, más probable es que el problema no ocurra.
EDITAR3!
He logrado establecer una distancia constante entre las celdas, no con la subclase del diseño, sino con mi propia memoria al guardar el origen y la altura de la celda anterior,así que tengo el espaciado constante pero el problema ha vuelto ! ¡parece que si las celdas están en cierta estructura, hace que el método de devolución de llamada que crea celdas no se llame a tiempo! wow, realmente me pregunto cómo nadie había visto esto antes ... aquí está mi implementación para crear espacios sin subclases, que también causan el problema:
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=@"Cell";
GridCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:@"%ld",(long)indexPath.row];
NSLog(@"%d",indexPath.row);
if(indexPath.row>1)
{
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-2 inSection:indexPath.section];
float prey=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"y:%ld",(long)ipPrev.row]] floatValue];
float preh=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"h:%ld",(long)ipPrev.row]] floatValue];
cell.frame=CGRectMake(cell.frame.origin.x, preh+prey+10, cell.frame.size.width, cell.frame.size.height);
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.origin.y forKey:[NSString stringWithFormat:@"y:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.size.height forKey:[NSString stringWithFormat:@"h:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"this index:%d",indexPath.row);
NSLog(@"this cell y:%f",cell.frame.origin.y);
NSLog(@"this cell height:%f",cell.frame.size.height);
NSLog(@"previous index:%ld",(long)ipPrev.row);
NSLog(@"previous cell y: %@",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"y:%ld",(long)ipPrev.row]]);
NSLog(@"previous cell height: %@",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"h:%ld",(long)ipPrev.row]]);
NSLog(@"------------------------");
}
return cell;
}