¿Cuál es la forma correcta de anular onMeasure ()? He visto varios enfoques. Por ejemplo, Professional Android Development usa MeasureSpec para calcular las dimensiones, luego termina con una llamada a setMeasuredDimension (). Por ejemplo:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}
Por otro lado, según esta publicación , la forma "correcta" es usar MeasureSpec, llamar a setMeasuredDimensions (), seguido de una llamada a setLayoutParams (), y terminar con una llamada a super.onMeasure (). Por ejemplo:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Entonces, ¿cuál es la forma correcta? Ninguno de los enfoques me ha funcionado al 100%.
Supongo que realmente lo que estoy preguntando es si alguien sabe de un tutorial que explique onMeasure (), diseño, dimensiones de vistas secundarias, etc.
android
android-layout
U Avalos
fuente
fuente
Respuestas:
Las otras soluciones no son completas. Pueden funcionar en algunos casos y son un buen lugar para comenzar, pero es posible que no se garantice que funcionen.
Cuando se llama a onMeasure, es posible que tenga o no los derechos para cambiar el tamaño. Los valores que se pasan a su onMeasure (
widthMeasureSpec
,heightMeasureSpec
) contienen información sobre lo que su vista secundaria puede hacer. Actualmente hay tres valores:MeasureSpec.UNSPECIFIED
- Puedes ser tan grande como quierasMeasureSpec.AT_MOST
- Tan grande como desee (hasta el tamaño de la especificación), esto esparentWidth
en su ejemplo.MeasureSpec.EXACTLY
- Sin elección. Padre ha elegido.Esto se hace para que Android pueda realizar varias pasadas para encontrar el tamaño correcto para cada elemento, consulte aquí para obtener más detalles.
Si no sigue estas reglas, no se garantiza que su enfoque funcione.
Por ejemplo, si desea comprobar si está autorizado a cambiar el tamaño, puede hacer lo siguiente:
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY; boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
Usando esta información sabrá si puede modificar los valores como en su código. O si se le pide que haga algo diferente. Una forma rápida y sencilla de resolver el tamaño deseado es utilizar uno de los siguientes métodos:
int resolveSizeAndState (int tamaño, int medidaSpec, int childMeasuredState)
int resolveSize (int tamaño, int medidaSpec)
Mientras que el primero solo está disponible en Honeycomb, el segundo está disponible en todas las versiones.
Nota: Puede encontrar eso
resizeWidth
oresizeHeight
siempre es falso. Descubrí que este era el caso si estaba solicitandoMATCH_PARENT
. Pude solucionar este problema solicitandoWRAP_CONTENT
en mi diseño principal y luego, durante la fase NO ESPECIFICADA, solicitando un tamaño deInteger.MAX_VALUE
. Hacerlo le da el tamaño máximo que su padre permite en el próximo paso a través de onMeasure.fuente
La documentación es la autoridad en este asunto: http://developer.android.com/guide/topics/ui/how-android-draws.html y http://developer.android.com/guide/topics/ui/custom -components.html
Para resumir: al final de su
onMeasure
método anulado debe llamarsetMeasuredDimension
.No debe llamar
super.onMeasure
después de llamarsetMeasuredDimension
, eso simplemente borrará lo que haya configurado. En algunas situaciones, es posible que desee llamar alsuper.onMeasure
primero y luego modificar los resultados llamandosetMeasuredDimension
.No llame
setLayoutParams
enonMeasure
. El diseño ocurre en una segunda pasada después de medir.fuente
Creo que depende del padre que está anulando.
Por ejemplo, si está ampliando un ViewGroup (como FrameLayout), cuando haya medido el tamaño, debe llamar como se muestra a continuación
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
porque es posible que desee que ViewGroup haga el trabajo de descanso (haga algunas cosas en la vista infantil)
Si está ampliando una Vista (como ImageView), puede simplemente llamar
this.setMeasuredDimension(width, height);
, porque la clase principal simplemente hará algo como lo ha hecho normalmente.En una palabra, si desea algunas funciones que su clase principal ofrece gratis, debe llamar
super.onMeasure()
(pasar MeasureSpec.EXACTLY modo medida especificación generalmente), de lo contrario, llamarthis.setMeasuredDimension(width, height);
es suficiente.fuente
así es como resolví el problema:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { .... setMeasuredDimension( measuredWidth, measuredHeight ); widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY ); heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Además, era necesario que el componente ViewPager
fuente
super.onMeasure
borrará las dimensiones establecidas usandosetMeasuredDimension
.Si cambia el tamaño de las vistas dentro de
onMeasure
todo lo que necesita es lasetMeasuredDimension
llamada. Si está cambiando el tamaño fuera deonMeasure
usted necesita llamarsetLayoutParams
. Por ejemplo, cambiar el tamaño de una vista de texto cuando se cambia el texto.fuente
Depende del control que esté utilizando. Las instrucciones de la documentación funcionan para algunos controles (TextView, Button, ...), pero no para otros (LinearLayout, ...). La forma en que funcionó muy bien para mí fue llamar al súper una vez que haya terminado. Basado en el artículo en el siguiente enlace.
http://humptydevelopers.blogspot.in/2013/05/android-view-overriding-onmeasure.html
fuente
Supongo que setLayoutParams y recalcular las medidas es una solución para cambiar el tamaño de las vistas secundarias correctamente, ya que esto generalmente se hace en el onMeasure de la clase derivada.
Sin embargo, esto rara vez funciona correctamente (por el motivo que sea ...), es mejor invocar a measureChildren (al derivar un ViewGroup) o intentar algo similar cuando sea necesario.
fuente
puede tomar este fragmento de código como ejemplo de onMeasure () ::
public class MyLayerLayout extends RelativeLayout { public MyLayerLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); int currentChildCount = getChildCount(); for (int i = 0; i < currentChildCount; i++) { View currentChild = getChildAt(i); //code to find information int widthPercent = currentChildInfo.getWidth(); int heightPercent = currentChildInfo.getHeight(); //considering we will pass height & width as percentage int myWidth = (int) Math.round(parentWidth * (widthPercent / 100.0)); int myHeight = (int) Math.round(parentHeight * (heightPercent / 100.0)); //Considering we need to set horizontal & vertical position of the view in parent AlignmentTraitValue vAlign = currentChildInfo.getVerticalLocation() != null ? currentChildlayerInfo.getVerticalLocation() : currentChildAlignmentTraitValue.TOP; AlignmentTraitValue hAlign = currentChildInfo.getHorizontalLocation() != null ? currentChildlayerInfo.getHorizontalLocation() : currentChildAlignmentTraitValue.LEFT; int topPadding = 0; int leftPadding = 0; if (vAlign.equals(currentChildAlignmentTraitValue.CENTER)) { topPadding = (parentHeight - myHeight) / 2; } else if (vAlign.equals(currentChildAlignmentTraitValue.BOTTOM)) { topPadding = parentHeight - myHeight; } if (hAlign.equals(currentChildAlignmentTraitValue.CENTER)) { leftPadding = (parentWidth - myWidth) / 2; } else if (hAlign.equals(currentChildAlignmentTraitValue.RIGHT)) { leftPadding = parentWidth - myWidth; } LayoutParams myLayoutParams = new LayoutParams(myWidth, myHeight); currentChildLayoutParams.setMargins(leftPadding, topPadding, 0, 0); currentChild.setLayoutParams(myLayoutParams); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
fuente