Respuestas:
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 :
TextView
. Pensé que tal vez querrían dibujar View
por ú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 TextView
también). Tal vez merece otra pregunta sobre StackOverflow :)?
invalidate()
y requestLayout()
) correctamente. El propósito de esos métodos es decir View
qué tipo de invalidación (como lo llamó) ha sucedido. No es como View
decidir qué camino seguir después de llamar a uno de esos métodos. La lógica detrás de elegir la View
ruta 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()
.
View
de alguna manera, por ejemplo, obtiene corrienteLayoutParams
de a View
y los modifica, pero NO llama a ninguno requestLayout
o setLayoutParams
(que llama requestLayout
internamente), puede llamar invalidate()
tanto como desee, y el View
no 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 View
que su tamaño ha cambiado (con una requestLayout
llamada al método), entonces el View
va a asumir que no lo hizo, y el onMeasure
y onLayout
no será llamado.
invalidate()
Las llamadas invalidate()
se realizan cuando desea programar un nuevo dibujo de la vista. Con el tiempo, se lo onDraw
llamará (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á onMeasure
y onLayout
no 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()
.
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.
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.
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)
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.
View
y descubriendo el problema yo mismo y depurándolo.
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()
?
requestLayout()
hace todo lo que forceLayout()
también hace.
forceLayout
tiene sentido. Entonces, al final, está muy mal nombrado y documentado.
invalidate()
---> onDraw()
del hilo de la interfaz de usuario
postInvalidate()
---> onDraw()
del hilo de fondo
requestLayout()
---> onMeasure()
y onLayout()
Y no necesariamente onDraw()
forceLayout()
---> onMeasure()
y onLayout()
SOLO SI el padre directo llamó requestLayout()
.