Tengo un UITableView con una lista de elementos. Seleccionar un elemento empuja un viewController que luego procede a hacer lo siguiente. desde el método viewDidLoad, disparo una URLRequest para los datos que requiere una de mis subvistas: una subclase UIView con drawRect anulado. Cuando los datos llegan de la nube, empiezo a construir mi jerarquía de vistas. la subclase en cuestión recibe los datos y su método drawRect ahora tiene todo lo que necesita para renderizar.
Pero.
Debido a que no llamo a drawRect explícitamente, Cocoa-Touch se encarga de eso, no tengo forma de informar a Cocoa-Touch que realmente quiero que se procese esta subclase de UIView. ¿Cuando? ¡Ahora estaría bien!
He probado [myView setNeedsDisplay]. Esto funciona a veces. Muy irregular.
He estado luchando con esto durante horas y horas. ¿Podría alguien que me brinde un enfoque sólido y garantizado para forzar una re-renderización de UIView?
Este es el fragmento de código que envía datos a la vista:
// Create the subview
self.chromosomeBlockView = [[[ChromosomeBlockView alloc] initWithFrame:frame] autorelease];
// Set some properties
self.chromosomeBlockView.sequenceString = self.sequenceString;
self.chromosomeBlockView.nucleotideBases = self.nucleotideLettersDictionary;
// Insert the view in the view hierarchy
[self.containerView addSubview:self.chromosomeBlockView];
[self.containerView bringSubviewToFront:self.chromosomeBlockView];
// A vain attempt to convince Cocoa-Touch that this view is worthy of being displayed ;-)
[self.chromosomeBlockView setNeedsDisplay];
Saludos, Doug
fuente
setNeedsDisplay
llamada real y la dedrawRect:
. Si bien la confiabilidad de la llamada está aquí, yo no llamaría a esta la solución “más robusta”; una solución de dibujo robusta debería, en teoría, hacer todo el dibujo inmediatamente antes de regresar al código del cliente que exige el dibujo.Tuve un problema con un gran retraso entre llamar a setNeedsDisplay y drawRect: (5 segundos). Resultó que llamé setNeedsDisplay en un hilo diferente al hilo principal. Después de mover esta llamada al hilo principal, el retraso desapareció.
Espero que esto sea de alguna ayuda.
fuente
La forma de devolución de dinero garantizada, de hormigón armado y sólido de forzar a que una vista se dibuje sincrónicamente (antes de volver al código de llamada) es configurar las
CALayer
interacciones de the con suUIView
subclase.En su subclase UIView, cree un
displayNow()
método que le diga a la capa que " establezca el rumbo para la visualización " y luego "lo haga así ":Rápido
C objetivo
También implemente un
draw(_: CALayer, in: CGContext)
método que llamará a su método de dibujo privado / interno (que funciona ya que cadaUIView
es aCALayerDelegate
) :Rápido
C objetivo
Y cree su
internalDraw(_: CGRect)
método personalizado , junto con a prueba de fallasdraw(_: CGRect)
:Rápido
C objetivo
Y ahora solo llame
myView.displayNow()
cuando realmente lo necesite para dibujar (como desde unaCADisplayLink
devolución de llamada) . NuestrodisplayNow()
método le diráCALayer
adisplayIfNeeded()
, que llamará de forma sincrónica a nuestrodraw(_:,in:)
y hará el dibujointernalDraw(_:)
, actualizando lo visual con lo que se dibuja en el contexto antes de continuar.Este enfoque es similar al de @ RobNapier anterior, pero tiene la ventaja de llamar
displayIfNeeded()
además desetNeedsDisplay()
, lo que lo hace sincrónico.Esto es posible porque los
CALayer
s exponen más funciones de dibujo que losUIView
s: las capas tienen un nivel más bajo que las vistas y están diseñadas explícitamente con el propósito de un dibujo altamente configurable dentro del diseño y (como muchas cosas en Cocoa) están diseñadas para usarse de manera flexible ( como clase principal, o como delegador, o como puente a otros sistemas de dibujo, o simplemente por sí mismos). El uso adecuado delCALayerDelegate
protocolo hace que todo esto sea posible.CALayer
Puede encontrar más información sobre la capacidad de configuración de s en la sección Configuración de objetos de capa de la Guía de programación de animación principal .fuente
drawRect:
dice explícitamente "Nunca debe llamar a este método directamente usted mismo". Además, CALayerdisplay
dice explícitamente "No llame a este método directamente". Si desea dibujarcontents
directamente en las capas sincrónicamente, no es necesario violar estas reglas. Puede dibujar en la capa encontents
cualquier momento que desee (incluso en hilos de fondo). Simplemente agregue una subcapa a la vista para eso. Pero eso es diferente a ponerlo en la pantalla, que necesita esperar hasta el momento de composición correcto.contents
("Si el objeto de la capa está vinculado a un objeto de vista, debe evitar establecer el contenido de esta propiedad directamente. La interacción entre las vistas y las capas generalmente resulta en la vista que reemplaza el contenido de esta propiedad durante una actualización posterior. ") No estoy recomendando particularmente este enfoque; el dibujo prematuro socava el rendimiento y la calidad del dibujo. Pero si lo necesita por alguna razón, entoncescontents
es cómo conseguirlo.drawRect:
directamente. No era necesario demostrar esta técnica y se ha corregido.contents
técnica que estás sugiriendo ... suena tentadora. Intenté algo así inicialmente, pero no pude hacer que funcionara, y descubrí que la solución anterior era mucho menos código sin ninguna razón para no tener el mismo rendimiento. Sin embargo, si tiene una solución funcional para elcontents
enfoque, me interesaría leerla (no hay ninguna razón por la que no pueda tener dos respuestas a esta pregunta, ¿verdad?)display
. Es solo un método público personalizado en una subclase de UIView, al igual que lo que se hace en GLKView (otra subclase de UIView, y el único escrito por Apple que conozco que exige la funcionalidad DRAW NOW! ).Tuve el mismo problema y todas las soluciones de SO o Google no funcionaron para mí. Por lo general,
setNeedsDisplay
funciona, pero cuando no ...Intenté llamar
setNeedsDisplay
a la vista de todas las formas posibles desde todos los hilos posibles y todo eso, pero todavía no tuve éxito. Sabemos, como dijo Rob, quePero por alguna razón no dibujaría esta vez. Y la única solución que he encontrado es llamarlo manualmente después de un tiempo, para dejar que todo lo que bloquee el sorteo pase, así:
Es una buena solución si no necesita que la vista vuelva a dibujar con mucha frecuencia. De lo contrario, si está haciendo algo en movimiento (acción), generalmente no hay problemas con solo llamar
setNeedsDisplay
.Espero que ayude a alguien que está perdido allí, como yo.
fuente
Bueno, sé que esto podría ser un gran cambio o incluso no ser adecuado para su proyecto, pero ¿consideró no realizar el empuje hasta que ya tenga los datos ? De esa manera, solo necesita dibujar la vista una vez y la experiencia del usuario también será mejor: el empuje se moverá ya cargado.
La forma en que lo hace es en la
UITableView
didSelectRowAtIndexPath
que solicita los datos de forma asincrónica. Una vez que recibe la respuesta, realiza manualmente la transición y pasa los datos a su viewController en formatoprepareForSegue
. Mientras tanto, es posible que desee mostrar algún indicador de actividad, para verificar el indicador de carga simple https://github.com/jdg/MBProgressHUDfuente