2011-02-18 15 views
9

Tengo una celda UITableView personalizada a la que he agregado un cuadro de texto para editar, que muestra y oculta en función del modo de edición. También intenté agregar una línea vertical que se muestra al editar, y lo hace, pero tengo algunos problemas de dibujo. Acabo de agregar una marca de verificación verde a la derecha para comenzar a trabajar en los comentarios de validación de entrada, y estoy viendo problemas similares.UITableViewCell personalizado vuelve a dibujar problemas

Aquí está el código para la celda y parte de mi cellForRowAtIndexPath.

#import <UIKit/UIKit.h> 

    @interface EditableCellStyle2 : UITableViewCell { 
     CGRect editRect; 
     UITextField *editField; 
     UIView *lineView; 
    } 

    @property (nonatomic, readonly, retain) UITextField *editField; 
    @property (nonatomic, readonly, retain) UIView *lineView; 

    @end 

#import "EditableCellStyle2.h" 


@implementation EditableCellStyle2 

@synthesize editField; 
@synthesize lineView; 


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 
    if (self) { 
     // Initialization code. 
     editRect = CGRectMake(83, 12, self.contentView.bounds.size.width-83, 19); 

     editField = [[UITextField alloc] initWithFrame:editRect]; 
     editField.font = [UIFont boldSystemFontOfSize:15]; 
     editField.textAlignment = UITextAlignmentLeft; 
     editField.textColor = [UIColor blackColor]; 
     editField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight; 

     [self.contentView addSubview:editField]; 

     self.editField.enabled = NO; 
     self.editField.hidden = YES; 


     lineView = [[UIView alloc] initWithFrame:CGRectMake(80, 0, 1, self.contentView.bounds.size.height)]; 
     self.lineView.backgroundColor = [UIColor lightGrayColor]; 
     [self.contentView addSubview:lineView]; 
     self.lineView.hidden = YES; 
    } 
    return self; 
} 

- (void)setSelected:(BOOL)selected animated:(BOOL)animated { 

    [super setSelected:selected animated:animated]; 

    // Configure the view for the selected state. 
} 

-(void)layoutSubviews 
{ 
    [super layoutSubviews]; // layouts the cell as UITableViewCellStyleValue2 would normally look like 

    editRect = CGRectMake(83, 12, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x-10, 19); 
    editField.frame = editRect; 
} 


- (void)willTransitionToState:(UITableViewCellStateMask)state { 
    [super willTransitionToState:state]; 

    if (state & UITableViewCellStateEditingMask) { 
     self.detailTextLabel.hidden = YES; 
     self.editField.enabled = YES; 
     self.lineView.hidden = NO; 
     self.editField.hidden = NO; 
    } 
} 

- (void)didTransitionToState:(UITableViewCellStateMask)state { 
    [super didTransitionToState:state]; 

    if (!(state & UITableViewCellStateEditingMask)) { 
     self.editField.enabled = NO; 
     self.editField.hidden = YES; 
     self.lineView.hidden = YES; 
     self.detailTextLabel.hidden = NO; 
     self.editField.text = self.detailTextLabel.text; 
    } 
} 


- (void)dealloc { 
    [editField release]; 
    [lineView release]; 

    [super dealloc]; 
} 


@end 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    // handling every section by hand since this view is essentially static. Sections 0, 1, 2, and 4 use a generic editable cell. 
    // Section 3 uses the multiline address cell. 

    static NSString *CellIdentifier = @"Cell"; 

    EditableCellStyle2 *cell = (EditableCellStyle2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    if (indexPath.section == 0 || indexPath.section == 1 || indexPath.section == 2 || indexPath.section == 4) { 
     if (cell == nil) { 
      cell = [[[EditableCellStyle2 alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease]; 
     } 
    } 

    // Configure the Odometer 
    if (indexPath.section == 0) { 
     NSArray *array = [sectionsArray objectAtIndex:indexPath.section]; 
     NSDictionary *dictionary = [array objectAtIndex:indexPath.row]; 

     cell.textLabel.text = @"Odometer"; 
     cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", [dictionary objectForKey:@"Odometer"]]; 
     cell.tag = kOdometer; 
     cell.editField.text = cell.detailTextLabel.text; 
     cell.editField.placeholder = @"Odometer"; 
     cell.editField.tag = kOdometer; 
     cell.editField.keyboardType = UIKeyboardTypeNumberPad; 

     // Create a view for the green checkmark for odometer input validation and set it as the right view. 
     UIImage *checkImage = [UIImage imageNamed:@"tick.png"]; 
     UIImageView *checkImageView = [[[UIImageView alloc] initWithImage:checkImage] autorelease]; 
     cell.editField.rightView = checkImageView; 
     cell.editField.rightViewMode = UITextFieldViewModeAlways; 
    } 

return cell; 
} 

No hay más que eso, pero todas las células se construyen de la misma manera.

Los problemas son que, cuando se está en el modo de edición, las líneas verticales se mostrarán correctamente. Cuando salgo del modo de edición, las celdas que estaban fuera de la pantalla cuando voy al modo normal siguen teniendo la línea vertical (no se oculta). Además, ahora que he agregado el imageView para el indicador de marca de verificación, las celdas que están fuera de la pantalla al cambiar de modo obtienen la marca de verificación. (solo la sección 0 lo configura).

También he notado que si hago cell.setNeedsDisplay, la etiqueta de texto y la etiqueta de texto de detalle no se actualizarán si la fuente de datos se ha actualizado. Tengo que hacer [self.tableView reloadData] que omite cualquier animación activa.

Estoy seguro de que estos problemas están relacionados con mi uso de una celda personalizada + dequeueReusableCellWithIdentifier, pero no puedo encontrar exactamente qué.

Cualquier comentario o impulso en la dirección correcta sería apreciado.

Editar: Al no utilizar las celdas reutilizables, parece que se han resuelto los problemas anteriores. Todavía estoy abierto a comentarios sobre el código de la celda. Olvidé otro problema que puede o no estar relacionado. Una de mis celdas tiene un botón "tocar para ver la lista". Si ingreso datos en las celdas mientras estoy en modo de edición, entonces presiono ese botón para elegir información de una lista (muestra una vista de tabla modal), cuando dejo de lado la vista modal, todos los datos editados de las celdas se han revertido a su estado original. No estoy llamando datos de recarga cuando descarto el controlador de vista modal. Pensé que esto podría solucionarse al no usar células reutilizables, pero no es así.

+0

Sí parece un problema con las células reutilizables. ¿Qué tan grande es tu tabla vista? Lo suficientemente grande como para justificar la reutilización de las células? ¿Si no los abandona y deja que la vista de tabla cree instancias individuales de sus celdas? – Rog

+0

La vista de tabla es bastante pequeña, es una vista detallada de una entrada de datos central. Tal vez 7 células, las tapas. Tengo la extraña sensación de haber estropeado las presentaciones de mi celular en alguna parte. – Chuck

+0

Estoy teniendo más o menos exactamente el mismo problema, por lo que agrego una recompensa en caso de que la gente lo note y lo ayude, ayudándome al mismo tiempo. Estoy bastante seguro de que es uno de esos doh! detalles, pero aún así :-) – niklassaers

Respuesta

8

Necesita preparar la celda para su reutilización. Trate de añadir esto a la aplicación EditableCellStyle2:

- (void)prepareForReuse { 
    [super prepareForReuse]; 
    [self didTransitionToState:UITableViewCellStateDefaultMask]; 
} 
+0

Oh mi. Madre de Dios. Todos mis problemas de actualización de desplazamiento en mi motor personalizado basado en UITableView ahora están corregidos. No tienes idea de cuánto dolor me has ahorrado. Si pudiera enviarte cervezas lo haría. Llamando al Papa ahora para que te presente como Santo Patrón de UITableViewCells. –

5

Tal vez recortado demasiado por su puesto, pero en el código publicado su manejo células reutilizable es un error.

En primer lugar, cada tipo diferente de celda necesita su propio CellIdentifier. En su caso (a juzgar por su comentario del código), eso significa al menos un identificador diferente para la sección 3 frente a las secciones 0, 1, 2 y 4. También puede querer hacer un identificador separado para la sección 0, por lo que no lo hace tiene que seguir eliminando y leyendo esa marca de verificación. El identificador diferente debe ser utilizado tanto para el dequeueReusableCellWithIdentifier: como para initWithStyle: reuseIdentifier: `para las secciones apropiadas.

El segundo problema es que no está restableciendo las celdas correctamente.Hay dos "tipos" de inicialización que deben hacerse a UITableViewCell: la inicialización es la misma para cada celda de su tipo, y la inicialización depende de la fila específica que se muestra. El primer tipo puede (y debe) solo hacerse una vez, cuando se asigna una nueva celda. El segundo tipo debe hacerse siempre a través de tableView:cellForRowAtIndexPath:. Parece que está haciendo la primera correctamente para su clase EditableTableCell2 en su método init, pero no veo ningún lugar donde realice la inicialización por fila: nunca restablece selected, o el estado de la celda, o el contenido del campo de edición, o elimine el checkImageView ya que está utilizando el mismo tipo de celda para la sección 0 en comparación con las otras secciones. Si lo desea, el restablecimiento selected, el estado y la eliminación de la imagen de la casilla de verificación y el contenido del campo se pueden realizar en prepareForReuse en su clase EditableTableCell2.

El tercer problema, que casi con toda seguridad se debe al recorte excesivo, es que nunca se crea esta celda de "dirección de varias líneas" para la sección 3. Acabará tal vez reutilizando una EditableTableCell2 aleatoria, o tal vez falle en una excepción desde el marco cuando devuelve nil desde tableView:cellForRowAtIndexPath:.

Cuestiones relacionadas