tag manager google android layout android-widget lifecycle measure

android - id de google tag manager



¿Cómo recuperar las dimensiones de una vista? (15)

Tengo una vista formada por TableLayout, TableRow and TextView . Quiero que se vea como una cuadrícula. Necesito obtener la altura y el ancho de esta cuadrícula. Los métodos getHeight() y getWidth() siempre devuelven 0. Esto sucede cuando formateo la cuadrícula dinámicamente y también cuando uso una versión XML.

¿Cómo recuperar las dimensiones para una vista?

Aquí está mi programa de prueba que usé en Debug para verificar los resultados:

import android.app.Activity; import android.os.Bundle; import android.widget.TableLayout; import android.widget.TextView; public class appwig extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.maindemo); //<- includes the grid called "board" int vh = 0; int vw = 0; //Test-1 used the xml layout (which is displayed on the screen): TableLayout tl = (TableLayout) findViewById(R.id.board); tl = (TableLayout) findViewById(R.id.board); vh = tl.getHeight(); //<- getHeight returned 0, Why? vw = tl.getWidth(); //<- getWidth returned 0, Why? //Test-2 used a simple dynamically generated view: TextView tv = new TextView(this); tv.setHeight(20); tv.setWidth(20); vh = tv.getHeight(); //<- getHeight returned 0, Why? vw = tv.getWidth(); //<- getWidth returned 0, Why? } //eof method } //eof class


¿Está intentando obtener tamaños en un constructor, o cualquier otro método que se ejecute ANTES de obtener la imagen real?

No obtendrá ninguna dimensión antes de que se midan realmente todos los componentes (ya que su xml no conoce el tamaño de la pantalla, las posiciones de los padres y lo que sea)

Intente obtener valores después de onSizeChanged () (aunque se puede llamar con cero), o simplemente espere cuando obtenga una imagen real.


A pesar de que la solución propuesta funciona, puede que no sea la mejor solución para cada caso porque se basa en la documentación para ViewTreeObserver.OnGlobalLayoutListener

Definición de la interfaz para que se invoque una devolución de llamada cuando cambie el estado de diseño global o la visibilidad de las vistas dentro del árbol de vistas.

lo que significa que se llama a muchas veces y no siempre se mide la vista (que tiene su altura y anchura determinada)

Una alternativa es usar ViewTreeObserver.OnPreDrawListener que se llama solo cuando la vista está lista para dibujarse y tiene todas sus medidas.

final TextView tv = (TextView)findViewById(R.id.image_test); ViewTreeObserver vto = tv.getViewTreeObserver(); vto.addOnPreDrawListener(new OnPreDrawListener() { @Override public void onPreDraw() { tv.getViewTreeObserver().removeOnPreDrawListener(this); // Your view will have valid height and width at this point tv.getHeight(); tv.getWidth(); } });


Como se mencionó FX, puede usar un OnLayoutChangeListener para la vista que desea rastrear.

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { // Make changes } });

Puede eliminar el oyente en la devolución de llamada si solo desea el diseño inicial.


Creo que el OP se ha ido hace mucho, pero en caso de que esta respuesta sea capaz de ayudar a futuros buscadores, pensé que publicaría una solución que he encontrado. He añadido este código en mi método onCreate() :

EDITADO: 07/05/11 para incluir el código de los comentarios:

final TextView tv = (TextView)findViewById(R.id.image_test); ViewTreeObserver vto = tv.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { LayerDrawable ld = (LayerDrawable)tv.getBackground(); ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0); ViewTreeObserver obs = tv.getViewTreeObserver(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { obs.removeOnGlobalLayoutListener(this); } else { obs.removeGlobalOnLayoutListener(this); } } });

Primero obtengo una referencia final a mi TextView (para acceder en el método onGlobalLayout() ). Luego, obtengo el ViewTreeObserver de mi TextView , y agrego un OnGlobalLayoutListener , anulando onGLobalLayout (no parece haber un método de superclase para invocar aquí ...) y agrego mi código que requiere conocer las medidas de la vista en este oyente. Todo funciona como se espera para mí, así que espero que esto pueda ayudar.



Está intentando obtener el ancho y la altura de un elemento que aún no se ha dibujado.

Si usa la depuración y se detiene en algún punto, verá que la pantalla de su dispositivo todavía está vacía, porque sus elementos aún no se han dibujado, por lo que no puede obtener el ancho y la altura de algo, eso aún no existe.

Y, podría estar equivocado, pero setWidth() no siempre se respeta, Layout establece los hijos y decide cómo medirlos (llamando a child.measure() ), por lo que si configura setWidth() , no se garantiza que obtenga Este ancho después del elemento será dibujado.

Lo que necesita es usar getMeasuredWidth() (la medida más reciente de su Vista) en algún lugar después de que la vista haya sido realmente dibujada.

Busque en el ciclo de vida de la Activity para encontrar el mejor momento.

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Creo que una buena práctica es usar OnGlobalLayoutListener siguiente manera:

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (!mMeasured) { // Here your view is already layed out and measured for the first time mMeasured = true; // Some optional flag to mark, that we already got the sizes } } });

Puede colocar este código directamente en onCreate() , y se invocará cuando se onCreate() vistas.


Intenté usar onGlobalLayout() para hacer un formato personalizado de TextView , pero como notó @George Bailey, onGlobalLayout() se llama dos veces: una vez en la ruta de diseño inicial y la segunda vez después de modificar el texto.

View.onSizeChanged() funciona mejor para mí porque si View.onSizeChanged() el texto allí, el método se llama solo una vez (durante el pase de diseño). Esto requirió una TextView de TextView , pero en API Level 11+ View. addOnLayoutChangeListener() View. addOnLayoutChangeListener() se puede utilizar para evitar sub-classing.

Una cosa más, para obtener el ancho correcto de la vista en View.onSizeChanged() , el layout_width debe configurarse como match_parent , no wrap_content .


Puede utilizar una difusión que se llama en OnResume ()

Por ejemplo:

int vh = 0; int vw = 0; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.maindemo); //<- includes the grid called "board" registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { TableLayout tl = (TableLayout) findViewById(R.id.board); tl = (TableLayout) findViewById(R.id.board); vh = tl.getHeight(); vw = tl.getWidth(); } }, new IntentFilter("Test")); } protected void onResume() { super.onResume(); Intent it = new Intent("Test"); sendBroadcast(it); }

No puede obtener la altura de una vista en OnCreate (), onStart () o incluso en onResume () por la razón por la que kcoppock respondió


Simplemente agregaré una solución alternativa, anularé el método onWindowFocusChanged de tu actividad y podrás obtener los valores de getHeight (), getWidth () desde allí.

@Override public void onWindowFocusChanged (boolean hasFocus) { // the height will be set at this point int height = myEverySoTallView.getMeasuredHeight(); }



Usa el método de publicación de la Vista como este

post(new Runnable() { @Override public void run() { Log.d(TAG, "width " + MyView.this.getMeasuredWidth()); } });



ViewTreeObserver y onWindowFocusChanged() no son tan necesarios en absoluto.

Si infla el TextView como diseño y / o coloca algo de contenido en él y configura LayoutParams , puede usar getMeasuredHeight() y getMeasuredWidth() .

Pero hay que tener cuidado con LinearLayouts (tal vez también otros ViewGroups ). El problema es que puede obtener el ancho y el alto después de onWindowFocusChanged() pero si intenta agregar algunas vistas en él, no podrá obtener esa información hasta que todo haya sido dibujado. Estaba tratando de agregar múltiples TextViews de TextViews a LinearLayouts para imitar un FlowLayout (estilo de LinearLayouts ) y no pude usar los Listeners . Una vez que se inicia el proceso, debe continuar de forma sincronizada. Por lo tanto, en tal caso, es posible que desee mantener el ancho en una variable para usarla más adelante, ya que durante la adición de vistas al diseño, es posible que lo necesite.


CORRECCIÓN: Descubrí que la solución anterior es terrible. Especialmente cuando su teléfono es lento. Y aquí, encontré otra solución: calcule el valor de px del elemento, incluidos los márgenes y los rellenos: dp a px: https://.com/a/6327095/1982712

o dimens.xml a px: https://.com/a/16276351/1982712

sp a px: https://.com/a/9219417/1982712 (invierta la solución)

o dimensionales a px: https://.com/a/16276351/1982712

y eso es.


Respuesta simple: Esto funcionó para mí sin problema. Parece que la clave es asegurarse de que la Vista tenga el enfoque antes de que consiga Hight, etc. Haga esto usando el método hasFocus (), y luego usando el método getHeight () en ese orden. Solo se requieren 3 líneas de código.

ImageButton myImageButton1 =(ImageButton)findViewById(R.id.imageButton1); myImageButton1.hasFocus();

int myButtonHeight = myImageButton1.getHeight();

Log.d("Button Height: ", ""+myButtonHeight );//Not required

Espero eso ayude.