Uso de forceLayout (), requestLayout () e invalidate ()


185

Estoy un poco confundido acerca de las funciones de forceLayout(), requestLayout()y invalidate()métodos de la Viewclase.

¿Cuándo serán llamados?

Respuestas:


357

Para comprender mejor las respuestas proporcionadas por François BOURLIEUX y Dalvik, le sugiero que eche un vistazo a este impresionante diagrama de ciclo de vida de Arpit Mathur : ingrese la descripción de la imagen aquí


28
A menudo veo que se llama a requestLayout directamente después de llamar a invalidar, incluso veo que eso sucede en el código fuente de Android para cosas como TextView, pero de acuerdo con este diagrama, es redundante, ¿verdad? Entonces, ¿hay algún propósito para hacer eso?
tcox

55
Bueno, esa es una pregunta interesante, y para ser honesto, realmente no sé por qué llaman a ambos métodos, por ejemplo TextView. Pensé que tal vez querrían dibujar Viewpor última vez antes de cambiar sus parámetros relacionados con el diseño, pero realmente no tiene ningún sentido si pensamos en que esas llamadas se invocan en un orden diferente (y llaman invalidate()inmediatamente después requestLayout()en TextViewtambién). Tal vez merece otra pregunta sobre StackOverflow :)?
Bartek Lipinski

14
(1/2) : No creo que entiendas esos dos métodos ( invalidate()y requestLayout()) correctamente. El propósito de esos métodos es decir Viewqué tipo de invalidación (como lo llamó) ha sucedido. No es como Viewdecidir qué camino seguir después de llamar a uno de esos métodos. La lógica detrás de elegir la Viewruta del ciclo de vida es elegir el método adecuado para llamarse a sí mismo. Si hay algo relacionado con el cambio de tamaño, requestLayout()debe llamarse, si solo hay un cambio visual sin un cambio de tamaño, debe llamar invalidate().
Bartek Lipinski

11
(2/2): si cambia el tamaño de su Viewde alguna manera, por ejemplo, obtiene corrienteLayoutParams de a Viewy los modifica, pero NO llama a ninguno requestLayouto setLayoutParams(que llama requestLayoutinternamente), puede llamar invalidate()tanto como desee, y el Viewno va a pasar por el proceso de medida de la disposición, por lo tanto, no va a cambiar su tamaño. Si no le dice al Viewque su tamaño ha cambiado (con una requestLayoutllamada al método), entonces el Viewva a asumir que no lo hizo, y el onMeasurey onLayoutno será llamado.
Bartek Lipinski


125

invalidate()

Las llamadas invalidate()se realizan cuando desea programar un nuevo dibujo de la vista. Con el tiempo, se lo onDrawllamará (pronto, pero no inmediatamente). Un ejemplo de cuándo una vista personalizada lo llamaría es cuando una propiedad de texto o color de fondo ha cambiado.

La vista se volverá a dibujar pero el tamaño no cambiará.

requestLayout()

Si algo sobre su vista cambia que afectará el tamaño, entonces debe llamar requestLayout(). Esto se activará onMeasurey onLayoutno solo para esta vista, sino también en toda la línea para las vistas principales.

No requestLayout()se garantiza queonDraw llamar resulte en un (contrario a lo que implica el diagrama en la respuesta aceptada), por lo que generalmente se combina con invalidate().

invalidate();
requestLayout();

Un ejemplo de esto es cuando una etiqueta personalizada tiene su propiedad de texto cambiada. La etiqueta cambiaría de tamaño y, por lo tanto, debe volverse a medir y volver a dibujar.

forceLayout()

Cuando requestLayout()se llama a un grupo de vista principal, no es necesario volver a medir y retransmitir sus vistas secundarias. Sin embargo, si un niño debe ser incluido en la nueva medición y retransmisión, entonces puede llamar forceLayout()al niño. forceLayout()solo funciona en un niño si ocurre junto con un requestLayout()en su padre directo. Llamar forceLayout()por sí solo no tendrá ningún efecto ya que no activa un requestLayout()árbol de la vista.

Lea estas preguntas y respuestas para obtener una descripción más detallada de forceLayout().

Estudio adicional


1
pero ¿no tendría más sentido primero llamar a requestLayout () y luego invalidar ()?
scholt

2
@scholt, por lo que sé, el orden no importa, por lo que puede llamar requestLayout()antes invalidate()si lo desea. Ninguno de los dos hace un diseño o dibuja de inmediato. Más bien, establecen banderas que eventualmente resultarán en un relevo y un nuevo dibujo.
Suragch

27

Aquí puede encontrar alguna respuesta: http://developer.android.com/guide/topics/ui/how-android-draws.html

Para mí, una llamada para invalidate()actualizar solo la vista y una llamada para requestLayout()actualizar la vista y calcular el tamaño de la vista en la pantalla.


3
¿Qué tal forceLayout () entonces?
sdabet

@fiddler, este método solo establece dos banderas: PFLAG_FORCE_LAYOUT y PFLAG_INVALIDATED
suitianshi

77
@suitianshi ¿Cuáles son las consecuencias de colocar las banderas entonces?
Sergey

1
@Sergey La consecuencia parece ser que este indicador anula el caché de medida (las vistas usan el caché para medir más rápido en el futuro para el mismo MeasureSpec); vea la línea 18783 de View.java aquí: github.com/android/platform_frameworks_base/blob/master/core/…
RhetoricalRuvim

3

utiliza invalidate () en una vista que desea volver a dibujar, hará que se invoque onDraw (Canvas c) y requestLayout () hará que todo el renderizado del diseño (fase de medición y fase de posicionamiento) vuelva a ejecutarse. Debe usarlo si está cambiando el tamaño de la vista secundaria en tiempo de ejecución, pero solo en casos particulares como restricciones de la vista principal (con esto quiero decir que la altura o el ancho principal son WRAP_CONTENT y, por lo tanto, mida los elementos secundarios antes de que puedan envolverlos nuevamente)


3

Esta respuesta no es correcta sobreforceLayout() .

Como puedes ver en el código deforceLayout() , simplemente marca la vista como "necesita una retransmisión", pero no programa ni desencadena esa retransmisión. El relevo no sucederá hasta que en algún momento en el futuro el padre de la vista se haya presentado por alguna otra razón.

También hay un problema mucho mayor al usar forceLayout()y requestLayout():

Digamos que has llamado forceLayout()a una vista. Ahora, al llamar requestLayout()a un descendiente de esa vista, Android recurrirá recursivamente requestLayout()a los antepasados ​​de ese descendiente. El problema es que detendrá la recursividad en la vista a la que ha llamado forceLayout(). Por lo tanto, la requestLayout()llamada nunca llegará a la raíz de la vista y, por lo tanto, nunca programará un pase de diseño. Un subárbol completo de la jerarquía de vistas está esperando un diseño y llamar requestLayout()a cualquier vista de ese subárbol no causará un diseño. Solo invocar requestLayout()cualquier vista fuera de ese subárbol romperá el hechizo.

Consideraría la implementación de forceLayout()(y cómo afecta requestLayout()que se rompa y nunca debe usar esa función en su código.


1
¡Hola! ¿Cómo se te ocurrió ese hechizo ? ¿Eso está documentado en alguna parte?
azizbekian

1
Desafortunadamente no está documentado y probablemente ni siquiera haya sido pensado. Lo descubrí investigando el código Viewy descubriendo el problema yo mismo y depurándolo.
fluidsonic

Entonces tengo curiosidad sobre el propósito de la forceLayout()API: en realidad no fuerza un pase de diseño, sino que simplemente cambia un indicador que se está observandoonMeasure() , pero onMeasure()no se llamará a menos que se llame requestLayout()un explícito View#measure(). Eso significa que forceLayout()debe ser emparejado con requestLayout(). Por otro lado, ¿por qué entonces actuar forceLayout()si todavía necesito hacerlo requestLayout()?
azizbekian

@azizbekian no, no tienes que hacerlo. requestLayout()hace todo lo que forceLayout()también hace.
fluidsonic

1
@Suragch se lo perdió, ¡gracias! Análisis muy interesante. El uso previsto de forceLayouttiene sentido. Entonces, al final, está muy mal nombrado y documentado.
fluidsonic

0

invalidate()---> onDraw()del hilo de la interfaz de usuario

postInvalidate()---> onDraw()del hilo de fondo

requestLayout()---> onMeasure()y onLayout()Y no necesariamente onDraw()

  • IMPORTANTE : Llamar a este método no afecta al hijo de la clase llamada.

forceLayout()---> onMeasure()y onLayout() SOLO SI el padre directo llamó requestLayout().

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.