Manera simple de hacer la disposición dinámica pero cuadrada

Estoy utilizando un GridView para mostrar un montón de vistas que son esencialmente LinearLayouts . Quiero que los LinearLayouts sean cuadrados, pero también quiero que sean de tamaño dinámico – es decir, hay dos columnas y quiero que LinearLayouts estire dependiendo del tamaño de la pantalla pero permanezca cuadrado. ¿Hay una manera de hacer esto a través de la disposición del xml o tengo que fijar las alturas y las anchuras programmatically?

Una solución ordenada para los elementos GridView cuadrados es extender RelativeLayout o LinearLayout y sobrescribir onMeasure manera:

 @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } 

No hay nada en el xml que le permitirá vincular las propiedades de ancho y altura. Probablemente lo más fácil de hacer es subclasificar LinearLayout y anular onMeasure

 @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int size = width > height ? height : width; setMeasuredDimension(size, size); } 

He utilizado esto para crear vistas que son siempre cuadrados antes. Debería seguir funcionando para un LinearLayout .

Más información que ayudará a hacer esto: http://developer.android.com/guide/topics/ui/custom-components.html http://developer.android.com/reference/android/view/View.MeasureSpec.html

He hecho de esta manera:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int size; if(widthMode == MeasureSpec.EXACTLY && widthSize > 0){ size = widthSize; } else if(heightMode == MeasureSpec.EXACTLY && heightSize > 0){ size = heightSize; } else{ size = widthSize < heightSize ? widthSize : heightSize; } int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); super.onMeasure(finalMeasureSpec, finalMeasureSpec); } 

Con esta implementación, su diseño será cuadrado, asumiendo el menor tamaño entre el ancho y la altura. Incluso se puede establecer con valores dinámicos, como usar el peso dentro de un LinearLayout.

Podemos hacerlo con una manera muy simple ~ Simplemente llame a super.onMeasure () dos veces ~

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); int squareLen = width; if (height > width) { squareLen = height; } super.onMeasure(MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY)); } 

Espero que pueda ayudarte ~

Puede ser tarde para responder, pero aún así, será útil para los nuevos visitantes.

Con el nuevo ConstraintLayout introducido en Android Studio 2.3, ahora es bastante fácil de construir diseños responsivos.

En un ConstraintLayout padre, para hacer que cualquiera de sus hijos vista / diseño dinámicamente cuadrados, agregue este atributo

 app:layout_constraintDimensionRatio="w,1:1" 

W es especificar restricciones de anchura y la proporción de 1: 1 asegura la disposición cuadrada.

Esta es una solución que funciona para todos los parámetros de diseño que se pueden configurar para ver o viewgroup:

  int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int widthDesc = MeasureSpec.getMode(widthMeasureSpec); int heightDesc = MeasureSpec.getMode(heightMeasureSpec); int size = 0; if (widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED) { size = DP(defaultSize); // Use your own default size, in our case // it's 125dp } else if ((widthDesc == MeasureSpec.UNSPECIFIED || heightDesc == MeasureSpec.UNSPECIFIED) && !(widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED)) { //Only one of the dimensions has been specified so we choose the dimension that has a value (in the case of unspecified, the value assigned is 0) size = width > height ? width : height; } else { //In all other cases both dimensions have been specified so we choose the smaller of the two size = width > height ? height : width; } setMeasuredDimension(size, size); 

Aclamaciones

Mi sugerencia es crear una clase de diseño personalizado que hereda de FrameLayout. Anule el método OnMeasure () y coloque el control que quiera que sea cuadrado dentro de SquareFrameLayout.

Así es como se hace en Xamarin.Android:

 public class SquareFrameLayout : FrameLayout { private const string _tag = "SquareFrameLayout"; public SquareFrameLayout(Android.Content.Context context):base(context) {} public SquareFrameLayout(IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer):base(javaReference, transfer) {} public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs):base(context, attrs) {} public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr):base(context, attrs, defStyleAttr) {} public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes):base(context, attrs, defStyleAttr, defStyleRes) {} protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { var widthMode = MeasureSpec.GetMode(widthMeasureSpec); int widthSize = MeasureSpec.GetSize(widthMeasureSpec); var heightMode = MeasureSpec.GetMode(heightMeasureSpec); int heightSize = MeasureSpec.GetSize(heightMeasureSpec); int width, height; switch (widthMode) { case MeasureSpecMode.Exactly: width = widthSize; break; case MeasureSpecMode.AtMost: width = Math.Min(widthSize, heightSize); break; default: width = 100; break; } switch (heightMode) { case MeasureSpecMode.Exactly: height = heightSize; break; case MeasureSpecMode.AtMost: height = Math.Min(widthSize, heightSize); break; default: height = 100; break; } Log.Debug(_tag, $"OnMeasure({widthMeasureSpec}, {heightMeasureSpec}) => Width mode: {widthMode}, Width: {widthSize}/{width}, Height mode: {heightMode}, Height: {heightSize}/{height}"); var size = Math.Min(width, height); var newMeasureSpec = MeasureSpec.MakeMeasureSpec(size, MeasureSpecMode.Exactly); base.OnMeasure(newMeasureSpec, newMeasureSpec); } } 

Si desea que una Vista (o cualquier otro control) sea cuadrada (y centrada), simplemente añádala a su diseño de la siguiente manera:

 <your.namespace.SquareFrameLayout android:id="@+id/squareContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"> <View android:id="@+id/squareContent" android:layout_width="match_parent" android:layout_height="match_parent" /> </your.namespace.SquareFrameLayout> 

Es tan simple como:

 public class SquareRelativeLayout extends RelativeLayout { public SquareRelativeLayout(Context context) { super(context); } public SquareRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (widthMeasureSpec < heightMeasureSpec) super.onMeasure(widthMeasureSpec, widthMeasureSpec); else super.onMeasure(heightMeasureSpec, heightMeasureSpec); } } 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.