GetWidth () y getHeight () de la vista devuelve 0

Estoy creando todos los elementos en mi proyecto androide dinámicamente. Estoy intentando conseguir la anchura y la altura de un botón de modo que pueda girar ese botón alrededor. Sólo estoy tratando de aprender a trabajar con el lenguaje android. Sin embargo, devuelve 0.

Hice algunas investigaciones y vi que tiene que hacerse en algún otro lugar que no sea en el método onCreate() . Si alguien me puede dar un ejemplo de cómo hacerlo, eso sería genial.

Aquí está mi código actual:

 package com.animation; import android.app.Activity; import android.os.Bundle; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.Button; import android.widget.LinearLayout; public class AnimateScreen extends Activity { //Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout ll = new LinearLayout(this); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); layoutParams.setMargins(30, 20, 30, 0); Button bt = new Button(this); bt.setText(String.valueOf(bt.getWidth())); RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2); ra.setDuration(3000L); ra.setRepeatMode(Animation.RESTART); ra.setRepeatCount(Animation.INFINITE); ra.setInterpolator(new LinearInterpolator()); bt.startAnimation(ra); ll.addView(bt,layoutParams); setContentView(ll); } 

Cualquier ayuda es apreciada.

Usted está llamando a getWidth() demasiado pronto. La interfaz de usuario no se ha dimensionado y presentado en la pantalla todavía.

Dudo que quieras hacer lo que estás haciendo, de todos modos – los widgets que se animan no cambian las áreas que se pueden hacer clic, por lo que el botón seguirá respondiendo a los clics en la orientación original independientemente de cómo se haya girado.

Dicho esto, puede utilizar un recurso de dimensión para definir el tamaño del botón y, a continuación, hacer referencia a ese recurso de dimensión desde el archivo de diseño y el código fuente para evitar este problema.

El problema básico es que hay que esperar la fase de dibujo para las mediciones reales (especialmente con valores dinámicos como wrap_content o match_parent ), pero normalmente esta fase no se ha terminado hasta onResume() . Por lo tanto, necesita una solución para esperar esta fase. Existen diferentes soluciones posibles a esto:

1. Escuche los Eventos de Dibujo / Diseño: ViewTreeObserver

Un ViewTreeObserver se activa para diferentes eventos de dibujo. Por lo general, el OnGlobalLayoutListener es lo que desea para obtener la medición, por lo que el código en el oyente será llamado después de la fase de diseño, por lo que las medidas 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 disparará en cada evento de diseño. Si tiene que soportar aplicaciones SDK Lvl <16 use esto para anular el registro del oyente:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2. Agregue un runnable a la cola de diseño: View.post ()

No muy conocido y mi solución favorita. Básicamente, sólo tiene que utilizar el método de post de la vista con su propio runnable. Esto básicamente pone en cola su código después de la medida de la vista, el diseño, etc, según lo declarado por Romain Guy :

La cola de eventos de la interfaz de usuario procesará los sucesos en orden. Después de invocar a setContentView (), la cola de eventos contendrá un mensaje solicitando un relayout, de modo que cualquier cosa que publique en la cola ocurrirá 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 sólo se ejecuta una vez y no tiene que deshabilitar el observador después de la ejecución que puede ser una molestia
  • Menos sintaxis detallada

Referencias:

3. Sobrescribir el método onLayout de Views

Esto sólo es práctico en cierta situación cuando la lógica puede ser encapsulada en la propia vista, 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 la mente, que onLayout se llamará muchas veces, por lo que ser considerado lo que haces en el método, o deshabilitar el 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 está ejecutando varias veces al crear el ui, puede utilizar el siguiente método de soporte v4 lib:

 View viewYouNeedHeightFrom = ... ... if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) { viewYouNeedHeightFrom.getHeight(); } 

Devuelve true si la vista ha pasado por, al menos, un diseño desde que se adjuntó o se separó de una ventana por última vez.

Adicional: Obtención de medidas estáticamente definidas

Si basta con obtener la altura / ancho definido estáticamente, sólo puede hacer esto con:

  • View.getMeasuredWidth()
  • View.getMeasuredHeigth()

Pero tenga en cuenta que esto podría ser diferente a la anchura / altura real después del dibujo. El javadoc describe la diferencia perfectamente:

El tamaño de una vista se expresa con una anchura y una altura. Una vista realmente posee dos pares de valores de anchura y altura.

El primer par se conoce como anchura medida y altura medida. Estas dimensiones definen el tamaño de una vista que quiere estar dentro de su matriz (vea el esquema para más detalles). Las dimensiones medidas se pueden obtener llamando a getMeasuredWidth () y getMeasuredHeight ().

El segundo par se conoce simplemente como anchura y altura, o a veces el ancho de dibujo y la altura de dibujo. Estas dimensiones definen el tamaño real de la vista en pantalla, en el tiempo de dibujo y después del diseño. Estos valores pueden, pero no tienen que ser, diferentes de la anchura y altura medidas. El ancho y la altura se pueden obtener llamando a getWidth () y getHeight ().

Nosotros podemos usar

 @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); //Here you can get the size! } 

He utilizado esta solución, que creo que es mejor que onWindowFocusChanged (). Si abre un DialogFragment, luego gire el teléfono, onWindowFocusChanged será llamado sólo cuando el usuario cierre el diálogo):

  yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Ensure you call it only once : yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this); // Here you can get the size :) } }); 

Editar: como removeGlobalOnLayoutListener está obsoleto, ahora debe hacer:

 @SuppressLint("NewApi") @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { // Ensure you call it only once : if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { container.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { container.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // Here you can get the size :) } 

Como indica Ian en este hilo de desarrolladores de Android :

De todos modos, el trato es que el diseño del contenido de una ventana sucede después de que todos los elementos se construyen y se agregan a sus vistas de los padres. Tiene que ser de esta manera, porque hasta que sepa qué componentes contiene una vista, y lo que contienen, etc., no hay ninguna forma razonable de poder distribuirlo.

En resumen, si llama a getWidth () etc. en un constructor, devolverá cero. El procedimiento consiste en crear todos los elementos de vista en el constructor y luego esperar a que el método onSizeChanged () de View se llame. En primer lugar, averigua su tamaño real, de modo que es cuando configura los tamaños de los elementos de la GUI.

Tenga en cuenta también que onSizeChanged () a veces se llama con parámetros de cero – compruebe este caso, y regrese inmediatamente (de modo que no obtenga una división por cero al calcular su diseño, etc.). Algún tiempo después será llamado con los valores reales.

Si necesita obtener el ancho de algún widget antes de que aparezca en la pantalla, puede utilizar getMeasuredWidth () o getMeasuredHeight ().

 myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); int width = myImage.getMeasuredWidth(); int height = myImage.getMeasuredHeight(); 

Prefiero usar OnPreDrawListener() lugar de addOnGlobalLayoutListener() , ya que se llama anteriormente.

  view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); // put your code here return false; } }); 
  • Detectar los límites de un documento en una imagen usando opencv java
  • Cómo ajustar la sensibilidad del micrófono mientras graba audio en android
  • LibGDX en la aplicación de compras y Gradle
  • Cómo depurar un servicio de fondo de Android?
  • Usando el descompilador jd-gui de java y obteniendo // ERROR INTERNO //
  • Valor de Json Parsing y Nullable int en android
  • Java / Android - Análisis Rápido de ByteBuffer
  • Android: trazado de dibujo como superposición en MapView
  • Parse crash en la creación de usuario
  • Android: implementación de la compatibilidad con el paquete de iconos
  • Iniciar y detener una notificación del receptor de emisión
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.