Android getMeasuredHeight devuelve valores erróneos!

Estoy tratando de determinar la dimensión real en píxeles de algunos elementos de interfaz de usuario!

Estos elementos se inflan desde un archivo .xml y se inicializan con anchura y altura de inmersión para que la interfaz gráfica de usuario finalmente soporte varios tamaños de pantalla y dpi ( según lo recomendado por las especificaciones de Android ).

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="150dip" android:orientation="vertical"> <ImageView android:id="@+id/TlFrame" android:layout_width="110dip" android:layout_height="90dip" android:src="@drawable/timeline_nodrawing" android:layout_margin="0dip" android:padding="0dip"/></LinearLayout> 

Este xml anterior representa un fotograma. Pero sí añadir muchos dinámicamente dentro de un diseño horizontal describir aquí:

 <HorizontalScrollView android:id="@+id/TlScroller" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_margin="0dip" android:padding="0dip" android:scrollbars="none" android:fillViewport="false" android:scrollbarFadeDuration="0" android:scrollbarDefaultDelayBeforeFade="0" android:fadingEdgeLength="0dip" android:scaleType="centerInside"> <!-- HorizontalScrollView can only host one direct child --> <LinearLayout android:id="@+id/TimelineContent" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_margin="0dip" android:padding="0dip" android:scaleType="centerInside"/> </HorizontalScrollView > 

El método definido para agregar un marco dentro de mi código java:

 private void addNewFrame() { LayoutInflater inflater = (LayoutInflater) _parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.tl_frame, null); TextView frameNumber = (TextView) root.findViewById(R.id.FrameNumber); Integer val = new Integer(_nFramesDisplayed+1); //+1 to display ids starting from one on the user side frameNumber.setText(val.toString()); ++_nFramesDisplayed; _content.addView(root); // _content variable is initialized like this in c_tor // _content = (LinearLayout) _parent.findViewById(R.id.TimelineContent); } 

Entonces dentro de mi código, trato de obtener el tamaño real real en píxel, porque necesito esto para dibujar algunas cosas opengl sobre ella.

 LayoutInflater inflater = (LayoutInflater) _parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.tl_frame, null); ImageView frame = (ImageView) root.findViewById(R.id.TlFrame); frame.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); frame.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); final int w = frame.getMeasuredWidth(); final int h = frame.getMeasuredHeight(); 

Todo parece funcionar bien, excepto que esos valores son mucho más grandes que el tamaño de píxel real de ImageView.

Informaciones reportadas de getWindowManager (). GetDefaultDisplay (). GetMetrics (métricas); Son los siguientes: densidad = 1,5 densidadDpi = 240 anchuraPixel = 600 alturaPixel = 1024

Ahora, sé que la regla de androide es: pixel = dip * (dpi / 160). Pero nada tiene sentido con el valor devuelto. Para que ImageView de (90dip X 110dip), los valores devueltos del método measure () es (270 x 218) que asumí está en píxel!

Alguien tiene alguna idea de por qué? ¿Es el valor devuelto en píxeles?

Por cierto: He estado probando el mismo código, pero con un TextView en lugar de un ImageView y todo parece estar funcionando bien! Por qué !?!?

Usted está llamando la measure incorrectamente.

MeasureSpec toma MeasureSpec valores que están especialmente embalados por MeasureSpec.makeMeasureSpec . measure ignora LayoutParams. Se espera que el padre que realiza la medición cree un MeasureSpec basado en su propia estrategia de medición y disposición y LayoutParams del niño.

Si desea medir la forma en que normalmente WRAP_CONTENT funciona en la mayoría de los diseños, measure llamada de la siguiente manera:

 frame.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)); 

Si no tiene valores máximos (por ejemplo, si está escribiendo algo como un ScrollView que tiene un espacio infinito), puede utilizar el modo UNSPECIFIED :

 frame.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 

Haz eso:

 frame.measure(0, 0); final int w = frame.getMeasuredWidth(); final int h = frame.getMeasuredHeight(); 

Resuelto

Okay ! Tipo de respuesta a mi propia pregunta aquí … Pero no completamente

1 – Parece que en algunos dispositivos, la medición de ImageView no proporciona valores exactos. He visto un montón de informes sobre este happenning en dispositivos Nexus y Galaxy, por ejemplo.

2 – Un trabajo alrededor de que he llegado con:

Establezca el ancho y la altura de su ImageView en "wrap_content" dentro del código xml.

Inflar el diseño dentro de su código (generalmente en la inicialización de IU supongo).

 LayoutInflater inflater = (LayoutInflater) _parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.tl_frame, null); ImageView frame = (ImageView) root.findViewById(R.id.TlFrame); 

Calcule su propia proporción para su vista de imagen, basada en el cálculo típico de Android

 //ScreenDpi can be acquired by getWindowManager().getDefaultDisplay().getMetrics(metrics); pixelWidth = wantedDipSize * (ScreenDpi / 160) 

Utilice el tamaño calculado para configurar su ImageView dinámicamente dentro de su código

 frame.getLayoutParams().width = pixeWidth; 

Y voila! Su ImageView tiene ahora el tamaño de Dip deseado;)

 view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @SuppressLint("NewApi") @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { //now we can retrieve the width and height int width = view.getWidth(); int height = view.getHeight(); //this is an important step not to keep receiving callbacks: //we should remove this listener //I use the function to remove it based on the api level! if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN){ view.getViewTreeObserver().removeOnGlobalLayoutListener(this); }else{ view.getViewTreeObserver().removeGlobalOnLayoutListener(this); } } }); 

Uno debe ir con Cómo obtener el ancho / altura de una vista

Probablemente, debido a lo que tienes en el archivo AndroidManifest.xml ( vínculo ) ya partir del cual se abre el directorio XXX del archivo xml, Android carga los recursos con la operación de escala. Usted decide usar "dip" ( enlace ) unidad de dimensión que es virtual y el valor real (px) puede ser diferente.

Tienes que crear Custom Textview y usarlo en tus diseños y usar la función de altura getActual para establecer la altura en tiempo de ejecución

 public class TextViewHeightPlus extends TextView { private static final String TAG = "TextViewHeightPlus"; private int actualHeight=0; public int getActualHeight() { return actualHeight; } public TextViewHeightPlus(Context context) { super(context); } public TextViewHeightPlus(Context context, AttributeSet attrs) { super(context, attrs); setCustomFont(context, attrs); } public TextViewHeightPlus(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); actualHeight=0; actualHeight=(int) ((getLineCount()-1)*getTextSize()); } } 

Desafortunadamente, en los métodos del ciclo de vida de la actividad , como Activity # onCreate (Bundle) , todavía no se ha realizado un pase de diseño, por lo que todavía no puede recuperar el tamaño de las vistas en la jerarquía de vistas. Sin embargo, puede pedir explícitamente a Android que mida una vista usando Ver # measure (int, int) .

Como señala la respuesta de @ adamp, tiene que proporcionar View # measure (int, int) con los valores de MeasureSpec , pero puede ser un poco desalentador descubrir el MeasureSpec correcto.

El siguiente método intenta determinar los valores MeasureSpec correctos y mide el pasado en view :

 public class ViewUtil { public static void measure(@NonNull final View view) { final ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); final int horizontalMode; final int horizontalSize; switch (layoutParams.width) { case ViewGroup.LayoutParams.MATCH_PARENT: horizontalMode = View.MeasureSpec.EXACTLY; if (view.getParent() instanceof LinearLayout && ((LinearLayout) view.getParent()).getOrientation() == LinearLayout.VERTICAL) { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); horizontalSize = ((View) view.getParent()).getMeasuredWidth() - lp.leftMargin - lp.rightMargin; } else { horizontalSize = ((View) view.getParent()).getMeasuredWidth(); } break; case ViewGroup.LayoutParams.WRAP_CONTENT: horizontalMode = View.MeasureSpec.UNSPECIFIED; horizontalSize = 0; break; default: horizontalMode = View.MeasureSpec.EXACTLY; horizontalSize = layoutParams.width; break; } final int horizontalMeasureSpec = View.MeasureSpec .makeMeasureSpec(horizontalSize, horizontalMode); final int verticalMode; final int verticalSize; switch (layoutParams.height) { case ViewGroup.LayoutParams.MATCH_PARENT: verticalMode = View.MeasureSpec.EXACTLY; if (view.getParent() instanceof LinearLayout && ((LinearLayout) view.getParent()).getOrientation() == LinearLayout.HORIZONTAL) { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); verticalSize = ((View) view.getParent()).getMeasuredHeight() - lp.topMargin - lp.bottomMargin; } else { verticalSize = ((View) view.getParent()).getMeasuredHeight(); } break; case ViewGroup.LayoutParams.WRAP_CONTENT: verticalMode = View.MeasureSpec.UNSPECIFIED; verticalSize = 0; break; default: verticalMode = View.MeasureSpec.EXACTLY; verticalSize = layoutParams.height; break; } final int verticalMeasureSpec = View.MeasureSpec.makeMeasureSpec(verticalSize, verticalMode); view.measure(horizontalMeasureSpec, verticalMeasureSpec); } } 

Entonces usted puede simplemente llamar:

 ViewUtil.measure(view); int height = view.getMeasuredHeight(); int width = view.getMeasuredWidth(); 

Alternativamente, como @Amit Yadav sugirió , puede utilizar OnGlobalLayoutListener para tener un oyente llamado después de que se haya realizado el pase de disposición. A continuación, se muestra un método que controla el anulación del registro del oyente y el método de nombrar los cambios en las versiones:

 public class ViewUtil { public static void captureGlobalLayout(@NonNull final View view, @NonNull final ViewTreeObserver.OnGlobalLayoutListener listener) { view.getViewTreeObserver() .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { viewTreeObserver.removeOnGlobalLayoutListener(this); } else { //noinspection deprecation viewTreeObserver.removeGlobalOnLayoutListener(this); } listener.onGlobalLayout(); } }); } } 

Entonces tú puedes:

 ViewUtil.captureGlobalLayout(rootView, new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int width = view.getMeasureWidth(); int height = view.getMeasuredHeight(); } }); 

Donde rootView puede ser la vista raíz de la vista jerárquica y la view puede ser cualquier vista dentro de su jerarquía que desee conocer las dimensiones de.

  • Android agrega elementos dinámicamente al recurso XML de matriz
  • Error en este XML: Error al analizar XML: prefijo no enlazado
  • Dpi valor de "grandes", "medio" y "pequeño" vistas de texto android
  • Android: ¿Acabo de tener un disparo por propiedad mediante el uso de temas? ¿No hay nada como CSS en Android?
  • Disposición de Android con vista a la derecha que ocupa un espacio preestablecido y visualiza en las escalas de la izquierda para llenar el resto de la pantalla hasta cierto límite
  • ¿Cómo se crean Fragmentos de preferencias y preferencias en Android?
  • Android - ¿Cómo alinear editText y enviar el botón inferior?
  • Deshabilitar el botón de envío del teclado cuando no se ha escrito nada
  • ¿Qué hay de malo en la cadena hardcoded en el archivo xml android?
  • Establecer la altura de la barra de herramientas mediante programación Android
  • Instanciar una clase interna (Preferencia) en un archivo xml
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.