2009-05-17 10 views
10

Tengo una vista personalizada en una celda de tabla personalizada. Cada vez que se cambia una propiedad específica en la vista personalizada, llamo al [self setNeedsDisplay], que vuelve a dibujar la vista en - (void)drawRect:(CGRect)rect. Esa propiedad se establece en el delegado de la vista de tabla tableView:cellForRowAtIndexPath:. Pero cuando la vista de tabla es más grande que la pantalla y las celdas deben reutilizarse, no se llama al drawRect cada vez que se encuentra setNeedsDisplay. Especialmente cuando muevo rápidamente la mesa. El desplazamiento lento funciona bien. Esto lleva a que la información en la primera y última celda a menudo sea incorrecta.setNeedsDisplay no siempre llama a drawRect

En el registro Veo que normalmente, para cada llamada a setNeedsDisplay hay una llamada a drawRect, pero cuando me desplazo rápidamente la vista de tabla hay más llamadas a setNeedsDisplay que drawRect. Seguramente debería haber una relación de uno a uno aquí.

Uso la misma vista personalizada en una UIView normal, y se vuelve a dibujar perfectamente cada vez que llamo al setNeedsDisplay. El problema parece estar aislado de las vistas de tabla y de la reutilización de celdas.

¿Alguien sabe lo que está pasando aquí? ¿Hay alguna otra manera de obligar a la vista personalizada a redibujarse?

Respuesta

13

Creo que tuve problemas con este problema durante casi una semana antes de encontrar el problema. Aquí está, y no es broma:

El puntero a esta vista personalizada se definió en el archivo .m en lugar del archivo .h, por lo que es una variable de clase en lugar de una variable de instancia.

Y sí, estoy muy, muy avergonzado.

1

Debería llamar al [_table_ reloadData] para volver a dibujar la tabla. No [_table_cell_ setNeedsDsiplay]

+0

No estoy redibujando la tabla. Solo la vista personalizada. – kareman

+1

reloadData llama a setNeedsDisplay en el momento adecuado. Usted parece estar luchando contra el marco. Deje que el marco decida cuáles actualizar e implemente tableView: cellForRowAtIndexPath: – amattn

+4

reloadData hace que se destruyan todas las celdas de la tabla, que se vuelva a consultar el origen de datos y que se recreen las celdas visibles. Eso es mucho más de lo necesario para actualizar una sola célula. – rpetrich

0

Parece que hay dos circunstancias en las que se actualiza la vista: si cambia el valor interno (y se llama a [self setNeedsDisplay] para forzar una actualización), y también si el tableview está solicitando una célula pueden extraer (o reutilizados) No estás rediseñando explícitamente esa vista personalizada en esa situación.

De acuerdo con los documentos:

delegado de la tabla general tableView: cellForRowAtIndexPath: debe siempre todo el contenido de reposición cuando la reutilización de una célula.

Si la vista de tabla está reciclando celdas, devolverá una celda con los valores anteriores todavía en su lugar. Depende de usted asegurarse de que el contenido esté actualizado. Dependiendo de cómo haya configurado su celda de tabla personalizada, es posible que tenga que hacer más para asegurarse de que la vista esté actualizada, pero lo más simple sería en el controlador de celda de tabla personalizada para forzar una llamada al [myCustomView setNeedsDisplay].

+0

Eso es lo que estoy haciendo. En tableView: cellForRowAtIndexPath: cambio los datos subyacentes para la vista personalizada y llamo a setNeedsDisplay en él. En el registro puedo ver que normalmente, para cada llamada a setNeedsDisplay hay una llamada a drawRect, pero cuando me desplazo rápidamente por la vista de tabla hay más llamadas a setNeedsDisplay que drawRect. Seguramente debería haber una relación de uno a uno aquí. – kareman

+1

Intenta desplazar la celda fuera de vista y hacia atrás para ver si el cambio entra en vigencia. Acabo de recordar que archivé un informe de error sobre este problema exacto (Error # 6022064: UITableViews y actualización de vistas de accesorios) el año pasado. Respondieron que no podían replicar el error. En mi caso, se llamó a un controlador de navegación, cambiaría el color de la vista de accesorios y se llamaría a setNeedsDisplay, pero cuando volvías, no se actualizaba. El desplazamiento de la celda fuera de la mesa y hacia atrás mostraría el color correcto. Si actúa de la misma manera y puedes aislarlo, tal vez puedas enviarlo y engañarlo. – Ramin

6

setNeedsDisplay sólo se llamará a drawRect: si la vista es visible, de lo contrario invalida capa de la vista y drawRect: se llamará cuando esté visible.

Al desplazarse por una vista de tabla, la vista de tabla solicitará celdas con la esperanza de agregarlas a la vista. Si se desplaza lo suficientemente rápido, algunas celdas tardarán demasiado en prepararse y, cuando estén listas, la ubicación en la que deberían colocarse estará fuera de la pantalla. En estos casos, la vista de tabla los descarta en lugar de agregarlos a la vista de desplazamiento (y por lo tanto drawRect: no se llamará)

+1

Además, setNeedsDisplay solo afecta la vista a la que se llama. Si es necesario, cualquier subvista debe ser invalidada independientemente – rpetrich

+0

Sonidos plausibles para tablas grandes, pero mi tabla tiene solo 10 filas, 8 de las cuales son visibles al mismo tiempo. ¿No se aplicaría esto solo si una celda viajó desde debajo de la mesa hasta arriba antes de poder volver a dibujarse? – kareman

+0

Sí, eso solo se aplicaría a las tablas grandes. En su tabla, las 8 filas visibles deberían recibir drawRect: ... si no, probablemente sea un error en alguna parte. ¿Puedes publicar tu código (o una versión simplificada que todavía tenga el error)? – rpetrich

Cuestiones relacionadas