java - studio - ¿Cuándo se llama View.onMeasure()?
propiedades de la clase view android (2)
Puede obtener las medidas de su vista personalizada en onSizeChanged
.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// use the provided width and height for whatever you need
}
Explicación
Cuando se crea una vista, este es el orden en que se llaman los siguientes métodos:
- Constructor
-
CustomView(Context context)
(si se crea mediante programación) -
CustomView(Context context, AttributeSet attrs)
(si se crea a partir de xml)
-
-
onFinishInflate
(asumiendo queonFinishInflate
el constructor xml) -
onAttachedToWindow
-
onMeasure
-
onSizeChanged
-
onLayout
-
onDraw
Lo más temprano que puede obtener las mediciones de la vista es en onMeasure
. Antes de eso el ancho y la altura son 0
. Sin embargo, lo único que debe hacer en onMeasure
es determinar el tamaño de la vista. Este método se llama varias veces mientras la vista le dice al padre qué tan grande quiere ser, pero el padre está determinando el tamaño final real. (Consulte esta respuesta para onMeasure
cómo se debe utilizar onMeasure
).
Si realmente desea utilizar el tamaño medido para cualquier cosa, el primer lugar para hacerlo es en el onSizeChanged
de onSizeChanged
. Se llama cuando se crea la vista porque el tamaño cambia de 0
a cualquiera que sea el tamaño.
También puede utilizar onLayout
, aunque, según tengo entendido, onLayout
es para personalizar cómo se onLayout
de su vista personalizada. También puede recibir llamadas con mayor frecuencia que onSizeChanged
, por ejemplo, si llama a requestLayout()
cuando el tamaño no ha cambiado realmente.
También puede acceder al tamaño en onDraw
con getMeasuredWidth()
y getMeasuredHeight()
. Sin embargo, si los está utilizando para realizar cálculos pesados, es mejor hacerlo de antemano. En términos generales, trate de mantener lo más alejado posible de onDraw
ya que puede llamarse varias veces. (Se llama cuando se invalidate()
).
Ver por ti mismo
Si no me cree, puede ver el orden de los eventos tal como se denominan en la vista personalizada a continuación. Aquí está la salida:
XML constructor called, measured size: (0, 0)
onFinishInflate called, measured size: (0, 0)
onAttachedToWindow called, measured size: (0, 0)
onMeasure called, measured size: (350, 1859)
onMeasure called, measured size: (350, 350)
onMeasure called, measured size: (350, 2112)
onMeasure called, measured size: (350, 350)
onSizeChanged called, measured size: (350, 350)
onLayout called, measured size: (350, 350)
onDraw called, measured size: (350, 350)
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.viewlifecycle.CustomView
android:id="@+id/customView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent"/>
</RelativeLayout>
CustomView.java
public class CustomView extends View {
private void printLogInfo(String methodName) {
Log.i("TAG", methodName + " called, measured size: (" + getMeasuredWidth() + ", " + getMeasuredHeight() + ")");
}
// constructors
public CustomView(Context context) {
super(context);
printLogInfo("Programmatic constructor");
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
printLogInfo("XML constructor");
}
// lifecycle methods
@Override
protected void onFinishInflate() {
super.onFinishInflate();
printLogInfo("onFinishInflate");
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
printLogInfo("onAttachedToWindow");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
printLogInfo("onMeasure");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
printLogInfo("onSizeChanged");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
printLogInfo("onLayout");
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
printLogInfo("onDraw");
}
}
Otras lecturas
Cuando es
View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)
¿llamado? Tengo una Activity que necesita realizar una acción después de que se haya llamado onMeasure .
Mi pregunta es la misma que la pregunta sin respuesta publicada aquí . La documentación de la View indica que se llama a requestLayout() cuando se llama a requestLayout() , que aparentemente la llama una vista en sí misma cuando cree que ya no puede encajar dentro de sus límites actuales.
Sin embargo, esto no me dice cuándo mi actividad puede suponer que mi View se ha medido. He usado este código para extender ImageView para formar TouchImageView. Se sugirió aquí que debería usar el método onMeasure para escalar mi imagen. Deseo actualizar el valor de un TextView después de que se haya medido ImageView para mostrar el porcentaje por el que se ha escalado la imagen.
Se llama a onMeasure cuando la Vista principal necesita calcular el diseño. Normalmente, se puede llamar a onMeasure varias veces dependiendo de los diferentes niños presentes y sus parámetros de diseño.
La mejor manera de hacer algo cuando se llama onMeasure es (creo) crear su propio control, extender ImageView y anular onMeasure (solo llame a super.onMeasure y haga lo que quiera).
Si lo hace, solo tenga en cuenta que en Measure puede llamarse varias veces con diferentes parámetros, por lo que lo que se mida puede no ser el ancho y la altura finales de lo que realmente se mostrará.