El problema básico es que debe esperar la fase de dibujo para las mediciones reales (especialmente con valores dinámicos como wrap_content
o match_parent
), pero por lo general esta fase no se ha completado onResume()
. Por lo tanto, necesita una solución alternativa para esperar esta fase. Hay diferentes soluciones posibles para esto:
1. Escuche los eventos de Draw / Layout: ViewTreeObserver
Se dispara un ViewTreeObserver para diferentes eventos de dibujo. Por lo general, esto OnGlobalLayoutListener
es lo que desea para obtener la medición, por lo que el código en el oyente se llamará después de la fase de diseño, para que las mediciones estén listas:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Nota: El oyente se eliminará inmediatamente porque, de lo contrario, se activará en cada evento de diseño. Si tiene que admitir aplicaciones SDK Lvl <16, use esto para cancelar el registro del oyente:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Agregue un ejecutable a la cola de diseño: View.post ()
No muy conocido y mi solución favorita. Básicamente, solo use el método de publicación de View con su propio ejecutable. Básicamente, esto pone en cola su código después de la medida, el diseño, etc. de la vista según lo declarado por Romain Guy :
La cola de eventos de la IU procesará los eventos en orden. Después de invocar setContentView (), la cola de eventos contendrá un mensaje pidiendo una retransmisión, por lo que todo lo que publique en la cola sucederá después del pase de diseño
Ejemplo:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
La ventaja sobre ViewTreeObserver
:
- su código solo se ejecuta una vez y no tiene que deshabilitar el Observador después de la ejecución, lo que puede ser una molestia
- sintaxis menos detallada
Referencias
3. Sobrescribir el método onLayout de Views
Esto solo es práctico en ciertas situaciones cuando la lógica se puede encapsular en la vista misma, de lo contrario, esta es una sintaxis bastante detallada y engorrosa.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
También tenga en cuenta que onLayout se llamará muchas veces, así que tenga en cuenta lo que hace en el método o desactive su código después de la primera vez
4. Compruebe si ha pasado por la fase de diseño
Si tiene código que se ejecuta varias veces mientras crea la interfaz de usuario, puede usar el siguiente método de soporte v4 lib:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Devuelve verdadero si la vista ha pasado por al menos un diseño desde la última vez que se adjuntó o desconectó de una ventana.
Adicional: obtener medidas estáticamente definidas
Si es suficiente obtener la altura / anchura estáticamente definidas, puede hacer esto con:
Pero tenga en cuenta que esto podría ser diferente al ancho / alto real después del dibujo. El javadoc describe la diferencia perfectamente:
El tamaño de una vista se expresa con un ancho y un alto. Una vista en realidad posee dos pares de valores de ancho y alto.
El primer par se conoce como ancho medido y altura medida. Estas dimensiones definen qué tan grande quiere ser una vista dentro de su elemento primario (consulte Diseño para obtener más detalles). Las dimensiones medidas se pueden obtener llamando a getMeasuredWidth () y getMeasuredHeight ().
El segundo par se conoce simplemente como ancho y alto, o a veces ancho y alto de dibujo. Estas dimensiones definen el tamaño real de la vista en pantalla, en el momento del dibujo y después del diseño. Estos valores pueden, pero no necesariamente, ser diferentes del ancho y la altura medidos. El ancho y el alto se pueden obtener llamando a getWidth () y getHeight ().