Tengo un UICollectionView con un FLowLayout. Funcionará como supongo que la mayoría de las veces, pero cada ahora y entonces una de las celdas no se ajusta correctamente. Por ejemplo, la de la celda que debe estar en la primera «columna» de la tercera fila si realmente al final en la segunda fila y sólo hay un espacio vacío donde debería estar (vea el diagrama a continuación). Todo se puede ver de esta rouge es la celda de la izquierda a la mano derecha (el resto es de corte) y el lugar que debe ser es vacío.

Esto no sucede de forma coherente; no es siempre la misma fila. Una vez que ha sucedido, no puede desplazarse hacia arriba y, a continuación, la espalda y la célula se ha fijado a sí mismo. O, al pulsar el celular (lo cual me lleva a la siguiente vista a través de un empate) y, a continuación, el pop de nuevo, voy a ver a la celda en la posición incorrecta y, a continuación, se saltará a la posición correcta.

De la velocidad de desplazamiento parece hacer más fácil para reproducir el problema. Cuando me desplazo lentamente, todavía puedo ver la celda en la posición incorrecta cada ahora y entonces, pero, a continuación, se saltará a la posición correcta en seguida.

El problema comenzó cuando he añadido las secciones insertos. Previamente, yo había las células casi a ras contra la recogida de los límites (poco, o sin márgenes) y no me di cuenta del problema. Pero esto significaba la derecha y a la izquierda de la vista de colección estaba vacía. Es decir, no podían desplazarse. Además, la barra de desplazamiento no fue vaciado a la derecha.

Puedo hacer que el problema ocurra en ambos Simulador y en un iPad 3.

Supongo que el problema que está sucediendo debido a la izquierda y a la derecha de la sección de inserciones… Pero si el valor es incorrecto, entonces yo sería de esperar que el comportamiento sea coherente. Me pregunto si esto podría ser un error con Apple? O tal vez esto es debido a una acumulación de los recuadros o algo similar.

UICollectionView flowLayout no envoltura de las células correctamente


Seguimiento: he estado utilizando esta respuesta a continuación por Nick hace más de 2 años sin problema (en el caso de personas que se están preguntando si hay agujeros en la respuesta – no he encontrado ninguna de momento). Bien hecho Nick.

InformationsquelleAutor lindon fox | 2012-10-17

11 Comentarios

  1. 92

    Hay un error en la UICollectionViewFlowLayout la implementación de layoutAttributesForElementsInRect que hace que devolver DOS objetos de atributo para una sola celda en ciertos casos relacionados con la sección de inserciones. Uno de los devuelven objetos de atributo no es válido (fuera de los límites de la vista de colección) y el otro es válida. A continuación es una subclase de UICollectionViewFlowLayout que el problema se soluciona mediante la exclusión de las celdas fuera de la vista de colección límites.

    //NDCollectionViewFlowLayout.h
    @interface NDCollectionViewFlowLayout : UICollectionViewFlowLayout
    @end
    
    //NDCollectionViewFlowLayout.m
    #import "NDCollectionViewFlowLayout.h"
    @implementation NDCollectionViewFlowLayout
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
      NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
      NSMutableArray *newAttributes = [NSMutableArray arrayWithCapacity:attributes.count];
      for (UICollectionViewLayoutAttributes *attribute in attributes) {
        if ((attribute.frame.origin.x + attribute.frame.size.width <= self.collectionViewContentSize.width) &&
            (attribute.frame.origin.y + attribute.frame.size.height <= self.collectionViewContentSize.height)) {
          [newAttributes addObject:attribute];
        }
      }
      return newAttributes;
    }
    @end

    Ver este.

    Otras respuestas sugieren que regresan SÍ de shouldInvalidateLayoutForBoundsChange, pero esto hace innecesario recomputations y no resuelve completamente el problema.

    Mi solución completamente soluciona el bug y no debe causar problemas cuando Apple corrige la causa raíz.

    • FYI este error también los cultivos con desplazamiento horizontal. Sustituyendo x por y y la anchura, la altura hace que este parche de trabajo.
    • Gracias! Yo estaba empezando a jugar con collectionView (si desea spam de Apple acerca de esto, he aquí el rdar de referencia openradar.appspot.com/12433891)
    • Gracias Patrick y Yanik. He actualizado mi respuesta para apoyar el desplazamiento vertical así.
    • Yo estaba teniendo este problema con PSTCollectionView y mi encabezados de sección no aparece en ios 5. He añadido [[attribute valueForKey:@"elementKind"] isEqualToString:@"UICollectionElementKindSectionHeader"] || a la si
    • Me topé con esta página hace un año y esta solucionado mi problema. Gracias! Sin embargo, me preguntaba si este problema ha sido resuelto internamente por Apple. Saludos.
    • En lugar de la comprobación individual de los parámetros de la rect, sólo podría utilizar CGRectIntersectsRect(attribute.frame, rect)
    • No, usted no desea comprobar si el rects se cruzan. De hecho, todas las células (válido o no) se cruzan los límites rect de la vista de colección. Desea comprobar si cualquier parte de la rect cae fuera de los límites, que es lo que mi código no.
    • Como de iOS 7.1, este error no ha sido fijado. Suspiro.
    • Gracias por conformes que. Yo estaba tan tentado a quitar esto de la base de código. Resulta que yo todavía lo necesitan. suspiro
    • Nick me estoy enfrentando el mismo problema después de usar la vista de colección dentro de la vista de la tabla de la célula.Las células dentro de la interna de vista de colección se reorganizan y a veces desaparece.Por favor me ayude, ¿cómo se supone que debo usuario su código.Yo soy sólo la creación de su diseño personalizado en lugar de UICollectionview diseño.Pero – (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect donde el uso de este método?
    • Tal vez estoy usando esta mal, pero en iOS 8.3 en Rápida, esta es la causa subvistas de la derecha, que se utiliza para cortar para que no aparezca. A alguien más?
    • No se han arreglado esto después de 3 años?

  2. 7

    descubrí problemas similares en mi aplicación para iPhone. La búsqueda de la Apple dev foro me trajo esta solución adecuada que trabajó en mi caso y, probablemente, en su caso también:

    Subclase UICollectionViewFlowLayout y reemplazar shouldInvalidateLayoutForBoundsChange para volver YES.

    //.h
    @interface MainLayout : UICollectionViewFlowLayout
    @end

    y

    //.m
    #import "MainLayout.h"
    @implementation MainLayout
    -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
        return YES;
    }
    @end
    • Esto sólo en parte se soluciona el problema que estoy teniendo con este problema. La función de la célula, en efecto, ir a la posición correcta cuando la fila aparece. Sin embargo, justo antes de que aparezca todavía tengo un celular que aparecen por el lateral.
    • Cuidado — esto hará que el diseño se ejecute cada vez que se desplaza. Esto puede tener un gran impacto en el rendimiento.
  3. 7

    Poner esto en el viewController que posee la colección

    - (void)viewWillLayoutSubviews
    {
        [super viewWillLayoutSubviews];
        [self.collectionView.collectionViewLayout invalidateLayout];
    }
    • ¿Qué hacer con eso?
    • En el viewController que posee la vista de colección
    • Mi problema fue que las células desaparecido por completo. Esta solución ayudado – sin embargo esto hace innecesario vuelve a cargar. Todavía se está trabajando ahora.. thx!
    • se produce un bucle infinito si llama desde el viewController para mí
    • Como se señaló por DHennessy13, esta solución actual es buena, pero puede ser imperfecta como es invalidateLayout cuando la rotación de la pantalla (y para la mayoría de los casos no debería). Una mejora podría ser la de establecer un indicador para invalidateLayout sólo una vez.
  4. 7

    Un Swift versión de Nick Snyder respuesta:

    class NDCollectionViewFlowLayout : UICollectionViewFlowLayout {
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
            let attributes = super.layoutAttributesForElements(in: rect)
            let contentSize = collectionViewContentSize
            return attributes?.filter { $0.frame.maxX <= contentSize.width && $0.frame.maxY < contentSize.height }
        }
    }
    • esta completamente hecha la CollectionViewCell desaparecer… Cualquier otra posible solución?
  5. 5

    He tenido este problema, así como para un básico gridview diseño con los insertos para los márgenes. La limitada depuración de lo que he hecho por ahora es la implementación de - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect en mi UICollectionViewFlowLayout subclase y por el registro de lo que el super implementación de la clase devuelve, lo que muestra claramente el problema.

    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *attrsList = [super layoutAttributesForElementsInRect:rect];
    
        for (UICollectionViewLayoutAttributes *attrs in attrsList) {
            NSLog(@"%f %f", attrs.frame.origin.x, attrs.frame.origin.y);
        }
    
        return attrsList;
    }

    Mediante la implementación de - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath también puedo ver que se parece a devolver los valores incorrectos para itemIndexPath.item == 30, que es factor de 10 de mi gridview del número de células por línea, no se si eso es relevante.

    - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
        UICollectionViewLayoutAttributes *attrs = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
    
        NSLog(@"initialAttrs: %f %f atIndexPath: %d", attrs.frame.origin.x, attrs.frame.origin.y, itemIndexPath.item);
    
        return attrs;
    }

    Con una falta de tiempo para obtener la depuración, la solución que he hecho por ahora es reducido mi collectionviews ancho, con un importe igual a los márgenes izquierdo y derecho. Tengo un encabezado que todavía necesita el ancho completo por lo que he clipsToBounds = NO en mi collectionview y, a continuación, también se elimina la izquierda y a la derecha insertos en ella, parece que funciona. Para el encabezado de la vista para, a continuación, permanecer en el lugar que usted necesita para implementar el desplazamiento de la estructura y el tamaño en el diseño de métodos que se encargan de devolver layoutAttributes para el encabezado de la vista.

    • Gracias por la información extra @monowerker. Creo que mi problema comenzó cuando he añadido el inserciones (yo he añadido esto a la pregunta). Voy a probar tus métodos de depuración y ver si se me dirá nada. Yo podría tratar de su trabajo alrededor de demasiado.
    • Esto es más probable que un error en UICFL/UICL, voy a probar y obtener un radar presentado cuando tengo el tiempo, aquí hay una discusión con algunos rdar-los números de referencia. twitter.com/steipete/status/258323913279410177
  6. 4

    He añadido un informe de errores a Apple. Lo que funciona para mí es establecer inferior sectionInset a un valor menor que el margen superior.

  7. 3

    Yo estaba experimentando la misma célula deplacing-problema en el iPhone con una UICollectionViewFlowLayout y por eso me ha encantado encontrar tu post. Yo sé que usted está teniendo el problema en un iPad, pero estoy publicando esto porque creo que es un problema general, con el UICollectionView. Así que aquí está lo que he averiguado.

    Puedo confirmar que el sectionInset es relevante para el problema. Además de que la headerReferenceSize también tiene influencia si una célula es deplaced o no. (Esto tiene sentido, ya que es necesaria para la calcuating el origen.)

    Por desgracia, incluso de diferentes tamaños de pantalla tienen que ser tomadas en cuenta. Cuando jugando con los valores de estas dos propiedades, he experimentado que una determinada configuración trabajado bien en ambos (3.5″ y 4″), en ninguno, o sólo en uno de los tamaños de pantalla. Generalmente ninguno de ellos. (Esto tiene sentido, ya que los límites de la UICollectionView cambios, por lo tanto yo no la experiencia de cualquier disparidad entre la retina y no retina.)

    He terminado la creación de la sectionInset y headerReferenceSize dependiendo del tamaño de la pantalla. Traté de alrededor de 50 combinaciones hasta encontrar los valores bajo los cuales el problema no ocurrir nunca más y el diseño visualmente aceptable. Es muy difícil encontrar los valores de los que trabajan en ambos tamaños de pantalla.

    Así que resumiendo, me pueden recomendar para jugar con los valores, la comprobación de estos en diferentes tamaños de pantalla y la esperanza de que Apple va a solucionar este problema.

  8. 3

    Sólo me he encontrado con un problema similar con las células de desaparecer después de UICollectionView de desplazamiento en iOS 10 (no tiene problemas en iOS 6-9).

    Subclases de UICollectionViewFlowLayout y método de reemplazo layoutAttributesForElementsInRect: no funciona en mi caso.

    La solución era bastante simple. Actualmente yo uso una instancia de UICollectionViewFlowLayout y establecer tanto itemSize y estimatedItemSize (yo no lo uso estimatedItemSize antes) y configurarlo para que no sea de tamaño cero.
    Tamaño real es el cálculo en collectionView:diseño:sizeForItemAtIndexPath: método.

    También, me he quitado una llamada de invalidateLayout método de layoutSubviews a fin de evitar innecesarias vuelve a cargar.

    • donde se puso el itemsize y estimatedItemsize en el uicollectionviewflowlayout?
    • Si usted cree CollectionView en el código, a continuación:
    • UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; [flowLayout setItemSize:CGSizeMake(200, 200)]; [flowLayout setEstimatedItemSize:CGSizeMake(200, 200)]; auto.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
    • Configuración de estimatedItemSize lo hizo por mí
  9. 2

    He experimentado un problema similar, pero encontraron una solución diferente.

    Estoy usando una implementación personalizada de UICollectionViewFlowLayout con un desplazamiento horizontal. También estoy creando personalizado marco de las ubicaciones de cada celda.

    El problema que tenía era que [super layoutAttributesForElementsInRect:rect] no era que se devuelvan todos los UICollectionViewLayoutAttributes que se debe mostrar en la pantalla. En las llamadas a [auto.collectionView reloadData] algunas de las células de repente se establece en oculto.

    Lo que terminé haciendo fue crear un NSMutableDictionary que en caché todos los UICollectionViewLayoutAttributes que he visto hasta ahora y, a continuación, incluir todos los elementos que sé que debe ser mostrado.

    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    
        NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
        NSMutableArray * attrs = [NSMutableArray array];
        CGSize calculatedSize = [self calculatedItemSize];
    
        [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
            NSIndexPath * idxPath = attr.indexPath;
            CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
            if (CGRectIntersectsRect(itemFrame, rect))
            {
                attr = [self layoutAttributesForItemAtIndexPath:idxPath];
                [self.savedAttributesDict addAttribute:attr];
            }
        }];
    
        //We have to do this because there is a bug in the collection view where it won't correctly return all of the on screen cells.
        [self.savedAttributesDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray * cachedAttributes, BOOL *stop) {
    
            CGFloat columnX = [key floatValue];
            CGFloat leftExtreme = columnX; //This is the left edge of the element (I'm using horizontal scrolling)
            CGFloat rightExtreme = columnX + calculatedSize.width; //This is the right edge of the element (I'm using horizontal scrolling)
    
            if (leftExtreme <= (rect.origin.x + rect.size.width) || rightExtreme >= rect.origin.x) {
                for (UICollectionViewLayoutAttributes * attr in cachedAttributes) {
                    [attrs addObject:attr];
                }
            }
        }];
    
        return attrs;
    }

    Aquí es la categoría de NSMutableDictionary que el UICollectionViewLayoutAttributes se guardan correctamente.

    #import "NSMutableDictionary+CDBCollectionViewAttributesCache.h"
    @implementation NSMutableDictionary (CDBCollectionViewAttributesCache)
    - (void)addAttribute:(UICollectionViewLayoutAttributes*)attribute {
    NSString *key = [self keyForAttribute:attribute];
    if (key) {
    if (![self objectForKey:key]) {
    NSMutableArray *array = [NSMutableArray new];
    [array addObject:attribute];
    [self setObject:array forKey:key];
    } else {
    __block BOOL alreadyExists = NO;
    NSMutableArray *array = [self objectForKey:key];
    [array enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *existingAttr, NSUInteger idx, BOOL *stop) {
    if ([existingAttr.indexPath compare:attribute.indexPath] == NSOrderedSame) {
    alreadyExists = YES;
    *stop = YES;
    }
    }];
    if (!alreadyExists) {
    [array addObject:attribute];
    }
    }
    } else {
    DDLogError(@"%@", [CDKError errorWithMessage:[NSString stringWithFormat:@"Invalid UICollectionVeiwLayoutAttributes passed to category extension"] code:CDKErrorInvalidParams]);
    }
    }
    - (NSArray*)attributesForColumn:(NSUInteger)column {
    return [self objectForKey:[NSString stringWithFormat:@"%ld", column]];
    }
    - (void)removeAttributesForColumn:(NSUInteger)column {
    [self removeObjectForKey:[NSString stringWithFormat:@"%ld", column]];
    }
    - (NSString*)keyForAttribute:(UICollectionViewLayoutAttributes*)attribute {
    if (attribute) {
    NSInteger column = (NSInteger)attribute.frame.origin.x;
    return [NSString stringWithFormat:@"%ld", column];
    }
    return nil;
    }
    @end
    • Estoy usando el desplazamiento horizontal, se me arregle el problema con la solución, pero después de la realización de pasar a otra vista y volvió, el tamaño del contenido parece estar mal cuando hay elementos adicionales que no se dividen en columnas de igual a igual.
    • He encontrado una solución para arreglar el problema en que la célula llegar oculto después de realizar la aplicación y volver a la vista de colección. Trate de no establecer estimatedItemSize en collectionViewFlowLayout; establecer itemSize directamente.
  10. 2

    Las respuestas anteriores no funcionan para mí, pero después de la descarga de las imágenes, que sustituyó a

    [self.yourCollectionView reloadData]

    con

    [self.yourCollectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];

    para actualizar y puede mostrar todas las células correctamente, puede intentar.

  11. 0

    Este podría ser un poco tarde, pero asegúrese de establecer sus atributos en prepare() si es posible.

    Mi problema fue que las células se establecen, a continuación, obtener la actualización en layoutAttributesForElements. Esto resultó en un efecto de parpadeo cuando las nuevas células quedó a la vista.

    Moviendo todo el atributo lógica en prepare, a continuación, establecer en UICollectionViewCell.apply() se elimina el parpadeo y creado mantequilla suave celda 😊

Dejar respuesta

Please enter your comment!
Please enter your name here