Determinación del tamaño de una vista de Android en tiempo de ejecución

Estoy intentando aplicar una animación a una vista en mi aplicación para Android después de que se cree mi actividad. Para ello, necesito determinar el tamaño actual de la vista y, a continuación, configurar una animación a escala del tamaño actual al nuevo tamaño. Esta parte se debe hacer en tiempo de ejecución, ya que la vista se escala a diferentes tamaños dependiendo de la entrada del usuario. Mi diseño está definido en XML.

Esto parece una tarea fácil, y hay un montón de preguntas tan en relación con esto, aunque ninguno que resuelto mi problema, obviamente. Así que tal vez estoy perdiendo algo obvio. Tengo una manija a mi vista por:

ImageView myView = (ImageView)getWindow().findViewById(R.id.MyViewID); 

Esto funciona bien, pero al llamar a getWidth() , getHeight() , getMeasuredWidth() , getLayoutParams().width , etc., todos ellos devuelven 0. También he intentado llamar manualmente measure() en la vista seguido de una llamada a getMeasuredWidth() , pero eso no tiene efecto.

He intentado llamar a estos métodos e inspeccionar el objeto en el depurador en onCreate() mi actividad y en onPostCreate() . ¿Cómo puedo determinar las dimensiones exactas de esta vista en tiempo de ejecución?

Utilice ViewTreeObserver en la vista para esperar el primer diseño. Sólo después del primer diseño se obtendrá getWidth () / getHeight () / getMeasuredWidth () / getMeasuredHeight ().

 ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); viewWidth = view.getWidth(); viewHeight = view.getHeight(); } }); } 

En realidad hay varias soluciones, dependiendo del escenario:

  1. El método seguro, funcionará justo antes de dibujar la vista, después de que la fase de diseño haya terminado:
 public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) { final OnPreDrawListener preDrawListener = new OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); runnable.run(); return true; } }; view.getViewTreeObserver().addOnPreDrawListener(preDrawListener); } 
  1. En algunos casos, es suficiente para medir el tamaño de la vista manualmente:
 view.measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); int width=view.getMeasuredWidth(); int height=view.getMeasuredHeight(); 
  1. Si tiene una vista personalizada que ha ampliado, puede obtener su tamaño en el método "onMeasure", pero creo que funciona bien sólo en algunos casos:
 protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final int newHeight= MeasureSpec.getSize(heightMeasureSpec); final int newWidth= MeasureSpec.getSize(widthMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

¿Está llamando a getWidth() antes de que la vista se getWidth() en la pantalla?

Un error común cometido por los nuevos desarrolladores de Android es utilizar el ancho y la altura de una vista dentro de su constructor. Cuando se llama al constructor de una vista, Android no sabe aún cuán grande será la vista, por lo que los tamaños se ponen a cero. Los tamaños reales se calculan durante la fase de disposición, que ocurre después de la construcción pero antes de que se dibuje algo. Puede utilizar el método onSizeChanged() para que se le notifique de los valores cuando se conozcan, o puede utilizar los getWidth() y getHeight() posteriormente, como en el método onDraw() .

Basándome en el consejo de @ mbaird, encontré una solución viable subclasificando la clase ImageView y reemplazando onLayout() . Luego creé una interfaz de observador que mi actividad implementó y pasó una referencia a sí misma a la clase, lo que le permitió contar la actividad cuando se terminó de calibrar.

No estoy 100% convencido de que esta es la mejor solución (de ahí mi no marcar esta respuesta como correcta todavía), pero funciona y de acuerdo con la documentación es la primera vez cuando se puede encontrar el tamaño real de una vista.

Aquí está el código para obtener el diseño mediante la sustitución de una vista si API <11 (API 11 incluye la función View.OnLayoutChangedListener):

 public class CustomListView extends ListView { private OnLayoutChangedListener layoutChangedListener; public CustomListView(Context context) { super(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (layoutChangedListener != null) { layoutChangedListener.onLayout(changed, l, t, r, b); } super.onLayout(changed, l, t, r, b); } public void setLayoutChangedListener( OnLayoutChangedListener layoutChangedListener) { this.layoutChangedListener = layoutChangedListener; } } public interface OnLayoutChangedListener { void onLayout(boolean changed, int l, int t, int r, int b); } 

Puedes consultar esta pregunta . Puede usar el método post () de View .

También me perdí alrededor de getMeasuredWidth() y getMeasuredHeight() getHeight() y getWidth() durante mucho tiempo ………. más tarde encontré que obtener el ancho y la altura de la vista en onSizeChanged() es el mejor Manera de hacer esto …….. usted puede obtener dinámicamente su ancho ACTUAL y la altura ACTUAL de su vista invalidando el método onSizeChanged( ).

Puede que quiera echar un vistazo a esto que tiene un fragmento de código elaborado. Nueva publicación de blog: cómo obtener las dimensiones de ancho y alto de un customView (extends View) en Android http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

Esto funciona para mí en mi onClickListener :

 yourView.postDelayed(new Runnable() { @Override public void run() { yourView.invalidate(); System.out.println("Height yourView: " + yourView.getHeight()); System.out.println("Width yourView: " + yourView.getWidth()); } }, 1); 

Utilice debajo del código, se da el tamaño de la vista.

 @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); Log.e("WIDTH",""+view.getWidth()); Log.e("HEIGHT",""+view.getHeight()); } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.