Estoy un poco confundido acerca de las funciones de forceLayout(), requestLayout()y invalidate()métodos de la Viewclase.
¿Cuándo serán llamados?
android
android-layout
android-view
sdabet
fuente
fuente


TextView. Pensé que tal vez querrían dibujarViewpor ú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 llamaninvalidate()inmediatamente despuésrequestLayout()enTextViewtambién). Tal vez merece otra pregunta sobre StackOverflow :)?invalidate()yrequestLayout()) correctamente. El propósito de esos métodos es decirViewqué tipo de invalidación (como lo llamó) ha sucedido. No es comoViewdecidir qué camino seguir después de llamar a uno de esos métodos. La lógica detrás de elegir laViewruta 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 llamarinvalidate().Viewde alguna manera, por ejemplo, obtiene corrienteLayoutParamsde aViewy los modifica, pero NO llama a ningunorequestLayoutosetLayoutParams(que llamarequestLayoutinternamente), puede llamarinvalidate()tanto como desee, y elViewno 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 alViewque su tamaño ha cambiado (con unarequestLayoutllamada al método), entonces elViewva a asumir que no lo hizo, y elonMeasureyonLayoutno será llamado.invalidate()Las llamadas
invalidate()se realizan cuando desea programar un nuevo dibujo de la vista. Con el tiempo, se loonDrawllamará (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áonMeasureyonLayoutno solo para esta vista, sino también en toda la línea para las vistas principales.No
requestLayout()se garantiza queonDrawllamar resulte en un (contrario a lo que implica el diagrama en la respuesta aceptada), por lo que generalmente se combina coninvalidate().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 llamarforceLayout()al niño.forceLayout()solo funciona en un niño si ocurre junto con unrequestLayout()en su padre directo. LlamarforceLayout()por sí solo no tendrá ningún efecto ya que no activa unrequestLayout()árbol de la vista.Lea estas preguntas y respuestas para obtener una descripción más detallada de
forceLayout().Estudio adicional
Viewcódigo fuentefuente
requestLayout()antesinvalidate()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 pararequestLayout()actualizar la vista y calcular el tamaño de la vista en la pantalla.fuente
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)
fuente
Esta respuesta no es correcta sobre
forceLayout().Como puedes ver en el código de
forceLayout(), 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()yrequestLayout():Digamos que has llamado
forceLayout()a una vista. Ahora, al llamarrequestLayout()a un descendiente de esa vista, Android recurrirá recursivamenterequestLayout()a los antepasados de ese descendiente. El problema es que detendrá la recursividad en la vista a la que ha llamadoforceLayout(). Por lo tanto, larequestLayout()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 llamarrequestLayout()a cualquier vista de ese subárbol no causará un diseño. Solo invocarrequestLayout()cualquier vista fuera de ese subárbol romperá el hechizo.Consideraría la implementación de
forceLayout()(y cómo afectarequestLayout()que se rompa y nunca debe usar esa función en su código.fuente
Viewy 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(), peroonMeasure()no se llamará a menos que se llamerequestLayout()un explícitoView#measure(). Eso significa queforceLayout()debe ser emparejado conrequestLayout(). Por otro lado, ¿por qué entonces actuarforceLayout()si todavía necesito hacerlorequestLayout()?requestLayout()hace todo lo queforceLayout()también hace.forceLayouttiene sentido. Entonces, al final, está muy mal nombrado y documentado.invalidate()--->onDraw()del hilo de la interfaz de usuariopostInvalidate()--->onDraw()del hilo de fondorequestLayout()--->onMeasure()yonLayout()Y no necesariamenteonDraw()forceLayout()--->onMeasure()yonLayout()SOLO SI el padre directo llamórequestLayout().fuente