¿Cómo recuperar las dimensiones de una vista?

Tengo una vista compuesta de tablelayout, plantrows y textviews. Quiero que se vea como una cuadrícula. Necesito obtener el alto y el ancho de esta grilla. Los métodos getheight () y getwidth () siempre devuelven 0. Esto ocurre cuando formateo la grilla dinámicamente y también cuando uso una versión xml.

¿Cómo recuperar las dimensiones de una vista?


Aquí está mi progtwig de prueba que utilicé 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 

Creo que el OP ya pasó, pero en caso de que esta respuesta sea capaz de ayudar a futuros buscadores, pensé en publicar una solución que he encontrado. He agregado 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() ). A continuación, obtengo el ViewTreeObserver de mi TextView y agrego un OnGlobalLayoutListener , reemplazando onGLobalLayout (no parece haber un método de superclase para invocar aquí …) y agregando mi código que requiere conocer las medidas de la vista en este oyente. Todo funciona como esperaba para mí, así que espero que esto pueda ayudar.

Solo 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(); } 

Está intentando obtener el ancho y alto de un elemento, que aún no se dibujó.

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

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

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

Mire 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 así:

 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 distribuyan las vistas.

Use el método de publicación de View como este

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

Traté de usar en onGlobalLayout() para hacer algunos formatos personalizados de TextView , pero como notó @George Bailey, onGlobalLayout() se llama dos veces: una vez en la ruta de diseño inicial y la segunda 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ó la TextView de TextView , pero en API Level 11+ View. addOnLayoutChangeListener() View. addOnLayoutChangeListener() se puede usar para evitar la subclasificación.

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

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

No obtendrá ninguna dimensión antes de medir realmente todos los componentes (dado que su xml no conoce su tamaño de visualización, las posiciones de los padres ni lo que sea)

Intenta obtener valores después de onSizeChanged () (aunque se puede llamar con cero), o simplemente esperando cuando obtendrás una imagen real.

Como se mencionó en FX, puede usar un OnLayoutChangeListener para la vista que quiere 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 callback si solo desea el diseño inicial.

Supongo que esto es lo que necesita mirar: use onSizeChanged() de su vista. Aquí hay un fragmento de código EXTENDIDO sobre cómo usar onSizeChanged() para obtener dinámicamente el alto y el ancho de su diseño o vista http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions .html

Más bien debería mirar el ciclo de vida de View: http://developer.android.com/reference/android/view/View.html. Por lo general, no debe conocer el ancho y la altura con certeza hasta que su actividad llegue al estado Reanudar.

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

Si TextView el TextView como diseño y / o TextView contenido en él y configuras LayoutParams , puedes usar getMeasuredHeight() y getMeasuredWidth() .

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

Puede usar una transmisió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 se puede obtener el alto de una vista en OnCreate (), onStart (), o incluso en onResume () por la razón que Kcoppock respondió

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

Definición de interfaz para una callback que se invocará cuando cambie el estado de disposición global o la visibilidad de las vistas dentro del árbol de vista.

lo que significa que se llama muchas veces y no siempre se mide la vista (tiene su altura y ancho determinados)

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(); } }); 

Respuesta simple: Esto funcionó para mí sin problema. Parece que la clave es asegurarse de que la Vista tenga el foco antes de obtener Height. Haga esto usando el método hasFocus () y luego 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.

Use getMeasuredWidth () y getMeasuredHeight () para su vista.

Guía del desarrollador: Ver

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

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

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

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

y eso es.