Estoy teniendo un problema con mi UICollectionView. Inicialmente se muestra fino, que muestra una cuadrícula de celdas, cada celda con una sola UIImageView. Estos UIImageViews están mostrando los archivos Png con transparencia que están almacenados en la aplicación del paquete.

Mi problema es, una vez que el UICollectionView ha sido desplazado, algunas de las células parecen estar dañado.

Un corrupto celda de muestra varias imágenes apiladas una encima de la otra, la parte superior de la imagen es la que se debe mostrar, y las imágenes de debajo son los que deben ser utilizados en otras células.

Mi mejor conjetura es que esto tiene algo que ver con la manera en que las células dentro de un UICollectionView son reutilizados, pero estoy abierto a sugerencias.

Este es el delegado de código que utilizo para la creación de las células dentro de la UICollectionView:

//creates the individual cells to go in the menu view
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    //create collection view cell
    UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];

    //create a uiview where we can place all views that need to go into this cell
    UIView * contents=[[UIView alloc] initWithFrame:cell.contentView.bounds];
    [contents setBackgroundColor:[UIColor clearColor]];
    [cell.contentView addSubview:contents];

    //add a button image
    NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]];
    UIImage * button=[UIImage imageWithContentsOfFile:buttonPath];
    UIImageView * buttonView=[[UIImageView alloc] initWithImage:button];
    [buttonView setContentMode:UIViewContentModeScaleAspectFit];
    [buttonView setFrame:contents.bounds];
    [contents addSubview:buttonView];

    //set tag to the indexPath.row so we can access it later
    [cell setTag:indexPath.row];

    //add interactivity
    UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
    [tap setNumberOfTapsRequired:1];
    [cell addGestureRecognizer:tap];

    //return the cell
    return cell;

}

Me puede dar más de código si es necesario.

¿Cómo puedo dejar de las células de corromper?

  • Tienes razón, es exactamente la manera que usted la reutilización de las Células. Porque estás añadiendo capa tras capa en su celda, con la addSubview: las llamadas.
InformationsquelleAutor Jimmery | 2013-10-09

7 Comentarios

  1. 42

    El problema es que se mantenga la adición de vistas a la UICollectionViewCell, ya que están siendo reutilizados automágicamente por el UICollectionView. Así que la vieja UIImageView‘s todavía están en la celda, como se va a añadir una más a medida que el cellForItemAtIndexPath: se llama.

    NO UTILICE addSubview:!

    Lugar que usted podría hacer que una celda personalizada con todos los puntos de vista que deseas ya está en ellos. De modo que cuando el cellForItemAtIndexPath: se llama usted sólo necesita establecer el contenido de este CustomCollectionViewCell lugar.

    De esta manera sin duda, va a dejar de ser dañado.


    Cómo construir un CustomCell.

    Paso1: Crear la .h & .clase m.

    CustomCell.h

    #import <UIKit/UIKit.h>
    
    @interface CustomCell : UICollectionViewCell
    {
        UIImageView *imageView;
    }
    
    @property (nonatomic, retain) UIImageView *imageView; //this imageview is the only thing we need right now.
    
    @end

    CustomCell.m

    #import "CustomCell.h"
    
    @implementation CustomCell
    
    @synthesize imageView;
    
    - (id)initWithFrame:(CGRect)aRect
    {
        if (self = [super initWithFrame:aRect])
        {
             //we create the UIImageView in this overwritten init so that we always have it at hand.
             imageView = [UIImageView alloc] init];
             //set specs and special wants for the imageView here.
             [self addSubview:imageView]; //the only place we want to do this addSubview: is here!
    
             //You wanted the imageView to react to touches and gestures. We can do that here too.
             UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
            [tap setNumberOfTapsRequired:1];
            [self addGestureRecognizer:tap];
    
    
            //We can also prepare views with additional contents here!
            //just add more labels/views/whatever you want.
        }
        return self;
    }
    
    -(void)onButtonTapped:(id)sender
    {
        //the response to the gesture.
        //mind that this is done in the cell. If you don't want things to happen from this cell.
        //then you can still activate this the way you did in your question.
    
    }

    Paso 2: a Importar!
    Ahora que hemos creado el CustomCell podemos importar en la clase que quiere usar.

    Paso 3: Uso en acción!

    //creates the individual cells to go in the menu view
    - (CustomCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
        //create collection view cell
        CustomCell *cell = (CustomCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"CustomCell" forIndexPath:indexPath]; //this is the place where the CustomCell does his magic.
        //Make sure to use the CustomCellReuseId that you register in the viewdidload/loadview (step4)
    
        //add a button image
        NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]];
    
        cell.imageView.image = [UIImage imageWithContentsOfFile:buttonPath]; //place the image on the CustemCell.imageView as we prepared.
    
        //set tag to the indexPath.row so we can access it later
        [cell setTag:indexPath.row]; //we don't need this to access the cell but I left this in for your personal want.
    
    /*
     * we can now do this from the CustomCell as well!
     *
        //add interactivity
        UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
        [tap setNumberOfTapsRequired:1];
        [cell addGestureRecognizer:tap];
    */
        //return the cell
        return cell;
    
    }

    Paso 4: Registro de la célula a la collectionView

    en el viewDidLoad /loadView añadir esta línea:

    [_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"CustomCell"];

    Paso5: ¡A Disfrutar!
    Su CustomCell se hace. Ahora hacer lo que te gusta y no te olvides de tomar un café demasiado.

    • se puede mostrar cómo me gustaría poner en práctica un CustomerCollectionViewCell ?
    • Por supuesto. Quieres que lo haga con conocimiento previo de un guión gráfico o código puro?
    • puro código por favor. I evitar el storyboard tanto como sea posible
    • Odio hacer esto en el guión demasiado 😛 de todos Modos, esto debe ser en código puro. Déjeme saber si todo está claro.
    • Gracias por hacer esto – Im jugar un poco con ella ahora – cuando cell.imageView=... se establece el UIImageView en la celda personalizada clase a un UIImage – si esto tiene sentido?
    • Ah sí debe ser .imageview.imagen = lade imagen; buena captura. Hay que ajustar la imagen a la que desea que sí. Usted puede establecer un marcador de posición en el customcell si desea que. Esto puede ser realmente útil si u de carga de las imágenes en un subproceso en segundo plano. De esta manera u puede pereza cargar cualquier imagen en cualquiera de las celdas cuando usted tiene una imagen termine de cargar. (al menos así es como yo lo he hecho con una de mis aplicaciones). También eres bienvenido 😉 me encanta hacer esto y ayudar.
    • ok, estoy teniendo «no reconocido selector» problemas, específicamente cuando uso el imageView propiedad de la celda personalizada – yo creo que con esta línea de CustomCell *cell=[collectionView dequeueReusable... – cuando me NSLog que me dice que es un UICollectionViewCell en lugar de un CustomCell
    • Ah usted necesita para lanzar el celular todavía. ^^ sólo un segundo de actualizar ahora. Probablemente debería hacer que el valor de retorno (CustomCell *) también. Estoy aquí hasta que esto se hace correctamente, con el fin de Ima de llegar de la u que responder a la necesidad de u!
    • Muchas gracias Totumus! Por desgracia, de fundición no parece tener ningún efecto – NSLogging que la célula todavía me dice que es un UICollectionViewCell y no un CustomCell
    • Ah veo cuál es el problema aquí:) deberá registrar el celular con el collectionview en el viewdidload (o vista de carga). El uso de este: [_collectionView registerClass:[CustomCell clase] forCellWithReuseIdentifier:@»UseACustomCellIdentifierThatWillbereusedlater»];
    • Tal vez usted tiene una sugerencia. Mi código está en busca de la misma como la suya, y para mí no funciona… stackoverflow.com/q/21334858/1933185
    • Gracias por esto, pensé que era una locura.
    • Se debe utilizar mageView = [[UIImageView alloc] initWithFrame:auto.contentView.límites];[self.contentView addSubview:imageView];
    • Mientras no lo hagan dentro de la cellForItemAtIndexPath: función. El CustomCell es totalmente personalizable para su propio diseño. Esta «costumbre»de células y todo lo que hay en su interior es ser correctamente utilizada por el sistema.
    • Totumus Maximus hay una manera de llegar a usted fuera de desbordamiento de pila? Estoy teniendo problemas para agregar una UIView a la costumbre de la célula sin hacer addSubview en el cellForItemAtIndexPath
    • Sí hay, sin embargo, este ejemplo no sólo de trabajo para UIImageViews. También se trabajará para custom UIViews. Basta con sustituir el imageview con una muestra aleatoria de UIView de su elaboración y probarlo 🙂 no necesitas mi ayuda, creo.
    • Sí he intentado. Yo ya lo tenía todo configurado pero me parece que no puede ir sin el uso de la addSubview. Mi UIView en mi CustomCell usa una clase personalizada y en algún lugar de su no ser inicializado por sí mismo.
    • También se pueden inicializar en el cellForItem supongo. Sólo asegúrese de que está todo preparado y añadido como antes. Hay casos en los que usted no quiere para preparar todo en el customcell debido a que las células cambia según la posición en la tabla. Esto no es un problema en absoluto. Sólo se necesita un método dentro de la CustomCell que hace todo lo que usted desea cambiar. Por ejemplo preparar una celda con una uiview como el anterior. A continuación, desea que la vista de un color diferente para cada fila. En este caso se desea un método que cambia el color en el interior de la CellForItem. Esto debería ser todo lo que usted necesita?
    • Voy a probar esto!
    • Mi costumbre de la célula no está vinculada a la de storyboard, así que mi única opción es añadir el uiimageview y la uilabel como una subvista. Es muy frustrante que el sistema de re-agrega la imagen en la parte superior de uno al otro. No hay otra forma de evitar esto?

  2. 6

    Justo después de

    UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];

    Sólo tiene que añadir esta línea,

    [[[cell contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
    • ¿cuál es la razón para que? Además, no funciona 🙁
  3. 4

    Que Suceder porque agrega cada vez que un UIImageView a su celda para solucionar este problema se tiene que Hacer una celda personalizada y, a continuación, utilizarlo como tomar:

    Personalizado.h

    #import <UIKit/UIKit.h>
    
    @interface CustomCell : UICollectionViewCell
    
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    
    @end

    Personalizado.m

    #import "CustomCell.h"
    
    @implementation CustomCell
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            //Initialization code
        }
        return self;
    }
    
    /*
    //Only override drawRect: if you perform custom drawing.
    //An empty implementation adversely affects performance during animation.
    - (void)drawRect:(CGRect)rect
    {
        //Drawing code
    }
    */
    
    @end

    Su Controlador

    - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
        CustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"CustomCell" forIndexPath:indexPath];
    
        NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]];
        UIImage * button=[UIImage imageWithContentsOfFile:buttonPath];
    
        [cell.imageView setImage:button];
    
        return cell;
    }

    Que también han de establecer ‘CustomCell’ como Identificador de la Celda en IB

  4. 2

    Para aquellos que están buscando un Swifty respuesta, añadir esta función a su CustomCell clase:

    override func prepareForReuse() {
        contentView.subviews.forEach({ $0.removeFromSuperview() })
        //replace contentView with the superview of the repeating content.
    }
    • Esto funcionó para mí genial. Para los principiantes significa que usted tiene que agregar la función de reemplazo de swift archivo donde se conectan los puntos de venta. ver class DeviceCollectionViewCell: UICollectionViewCell { @IBOutlet weak var deviceName: UILabel! @IBOutlet weak var Capability: UILabel! @IBOutlet weak var brandLabel: UILabel! @IBOutlet weak var SVGIconview: UIView! override func prepareForReuse() { SVGIconview.subviews.forEach({ $0.removeFromSuperview() }) } }
  5. 1

    Esto es para quitar duplicados de texto de la etiqueta en uicollectionviewcell.

    //Viewdidload
    [_collectionView registerClass:[UICollectionviewcell class]     forCellWithReuseIdentifier:@"cellIdentifier"];
    
    
    
    //in this method create label like this
    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
      {
         UICollectionViewCell *cell=[collectionView   dequeueReusableCellWithReuseIdentifier:@"cellidentifier" forIndexPath:indexPath];
         for (UILabel *lbl in cell.contentView.subviews)
            {
                if ([lbl isKindOfClass:[UILabel class]])
                {
                    [lbl removeFromSuperview];
                }
            }
         UILabel *nameLbl=[[UILabel alloc] initWithFrame:CGRectMake(0, 10, 50, 20)];
         nameLbl.text=[Array objectAtIndex:indexpath.row];                                                                                                                                  
         nameLbl.textColor=[UIColor whiteColor];
         [cell.contentView addSubview:nameLbl];
         return cell;
    
       }
  6. 0

    Para cualquier persona que es la adición de UICollectionView mediante programación y la costumbre de tener un celular, en otras palabras no XIB archivo, entonces usted tiene que añadir esta línea a viewDidLoad

    [_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
    • Yo no sé cómo esto se soluciona el problema.
  7. -1
    for (UIView *prevSubview in cell.contentView.subviews) {
        [prevSubview removeFromSuperview];
    }
    • Esta es la forma de eliminarlos, pero no deberían ser generados de manera que no necesite para eliminarlos
    • esto es útil cuando la colección anterior de la vista del contenido de la celda tiene una subvista y desea quitar y agregue un nuevo subvista. este sería el caso cuando usted está estableciendo como una imagen de la vista .
    • Describir lo que post!!!

Dejar respuesta

Please enter your comment!
Please enter your name here