programacion - Determinar el tamaño de una vista de Android en tiempo de ejecución
manual de programacion android pdf (10)
Estoy intentando aplicar una animación a una vista en mi aplicación de Android después de que se crea mi actividad. Para hacer esto, necesito determinar el tamaño actual de la vista y luego configurar una animación para escalar desde el tamaño actual al nuevo tamaño. Esta parte debe hacerse en tiempo de ejecución, ya que la vista se adapta 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 muchas preguntas sobre esto, aunque ninguna que resolvió mi problema, obviamente. Entonces quizás me esté perdiendo algo obvio. Entiendo mi punto de vista por:
ImageView myView = (ImageView)getWindow().findViewById(R.id.MyViewID);
Esto funciona bien, pero al llamar a getWidth()
, getHeight()
, getMeasuredWidth()
, getLayoutParams().width
, etc., todos devuelven 0. También he intentado llamar manualmente a measure()
en la vista seguido de una llamada a getMeasuredWidth()
, pero eso no tiene ningún efecto.
Intenté llamar a estos métodos e inspeccionar el objeto en el depurador en onCreate()
mi actividad y en onPostCreate()
. ¿Cómo puedo averiguar las dimensiones exactas de esta vista en tiempo de ejecución?
¿Está llamando a getWidth()
antes de que la vista se getWidth()
realmente en la pantalla?
Un error común que cometen los nuevos desarrolladores de Android es usar el ancho y alto de una vista dentro de su constructor. Cuando se llama al constructor de una vista, Android aún no sabe qué tan grande será la vista, por lo que los tamaños se establecen en cero. Los tamaños reales se calculan durante la etapa de diseño, que ocurre después de la construcción pero antes de que se dibuje nada. Puede utilizar el método
onSizeChanged()
para recibir notificaciones de los valores cuando se conocen, o puede usar losgetWidth()
ygetHeight()
más adelante, como en el métodoonDraw()
.
Aquí está el código para obtener el diseño al anular 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);
}
De acuerdo con el consejo de @ mbaird, encontré una solución viable al crear una subclasificación de la clase ImageView
y anular onLayout()
. Luego creé una interfaz de observador que mi actividad implementó y pasó una referencia a sí mismo a la clase, lo que le permitió decir la actividad cuando realmente se terminó de dimensionar.
No estoy 100% convencido de que esta es la mejor solución (de ahí que no marque esta respuesta como correcta), pero funciona y según la documentación es la primera vez que uno puede encontrar el tamaño real de una vista.
En realidad, hay varias soluciones, según el escenario:
- El método seguro, funcionará justo antes de dibujar la vista, después de que la fase de diseño haya finalizado:
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); }
Uso de muestra:
ViewUtil.runJustBeforeBeingDrawn(yourView, new Runnable() {
@Override
public void run() {
//Here you can safely get the view size (use "getWidth" and "getHeight"), and do whatever you wish with it
}
});
- En algunos casos, es suficiente para medir el tamaño de la vista de forma manual:
view.measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); int width=view.getMeasuredWidth(); int height=view.getMeasuredHeight();
- si tiene una vista personalizada que ha extendido, puede obtener su tamaño en el método "onMeasure", pero creo que funciona bien solo 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); }
Si escribe en Kotlin, puede usar la siguiente función, que detrás de las escenas funciona exactamente como
runJustBeforeBeingDrawn
que he escrito:view.doOnPreDraw { actionToBeTriggered() }
Tenga en cuenta que debe agregar esto a Gradle (encontrado here ):
implementation ''androidx.core:core-ktx:#.#''
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);
También me perdí en getMeasuredWidth()
y getMeasuredHeight()
getHeight()
y getWidth()
durante mucho tiempo .......... más tarde descubrí que obtener el ancho y alto de la vista en onSizeChanged()
es lo mejor forma de hacerlo ........ puede obtener dinámicamente su ancho ACTUAL y la altura ACTUAL de su vista anulando el método onSizeChanged(
).
podría echarle 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 una vista personalizada (extiende la vista) en Android http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html
Use ViewTreeObserver en la Vista para esperar el primer diseño. Solo después del primer diseño, getWidth () / getHeight () / getMeasuredWidth () / getMeasuredHeight () funcionan.
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();
}
});
}
Use el código a continuación, se le da el tamaño de vista.
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.e("WIDTH",""+view.getWidth());
Log.e("HEIGHT",""+view.getHeight());
}
Usted puede verificar esta pregunta . Puede usar el método post() View
.
funciona perfecto para mí:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
CTEditor ctEdit = Element as CTEditor;
if (ctEdit == null) return;
if (e.PropertyName == "Text")
{
double xHeight = Element.Height;
double aHaight = Control.Height;
double height;
Control.Measure(LayoutParams.MatchParent,LayoutParams.WrapContent);
height = Control.MeasuredHeight;
height = xHeight / aHaight * height;
if (Element.HeightRequest != height)
Element.HeightRequest = height;
}
}