All Articles

Flexlayout

Me gustaría antes de comenzar, que este post forma parte del primer calendario de adviento de xamarin en Español. Una iniciativa ideada por Luis Beltrán. Desde el día 1 hasta el 28 de Diciembre la comunidad de Xamarin colabora escribiendo un post o un vídeo. Os dejo un enlace donde podréis consultar todo el contenido que se ha generado aquí.

Un vez hecha la introducción, vamos al lio.

Flexlayout llego en la versión 3.5 de Xamarin Forms y posiblemente al llegar más tarde que otros layout es un “desconocido” a la hora de optar por este layout para nuestras pantallas. Por lo general en Xamarin Forms se opta por un grid o un stacklayout para maquetar pantallas.

¿Qué es Flexlayout?

FlexLayout es un layout que nos proporciona de manera eficiente varias formas de asignar nuestras vistas (controles) en la pantalla, facilitándonos el diseño, la alineación de nuestras vistas y la distribución del espacio entre nuestras vistas y la pantalla.

Este layout es muy interesante por que nos proporciona un mejor tamaño proporcional para las vistas, debido a que organiza las vistas en un proporción basada en las dimensiones de nuestra pantalla y entre las vistas de la pantalla.

Para empezar a usar FlexLayout basta con añadir a nuestra página el siguiente código:

<FlexLayout>
	// Resto del código
</FlexLayout>

Propiedades de Flexlayout

Una de las propiedades más importantes es Direction la cual contiene los siguientes valores:

Row, al usar está propiedad indicamos que los elementos dentro del contenedor se colocarán de forma ordenada de izquierda a derecha, es decir, de forma horizontal. En el mundo “flexible” no se usa la palabra horizontal, sino, eje principal (main-axis)

Column, al usar está propiedad indicamos que los elementos dentro del contenedor se van a colocar en forma de stack, de arriba a abajo. En el mundo “flexible” no se usa la palabra stack o vertical, sino, eje transversal (cross-axis).

Nota: Algunas propiedades de FlexLayout que se mencionaran a continuación se aplica solo al eje principal o al eje transversal.

RowReverse, lo mismo que row pero con la diferencia que los elementos se colocarán de derecha a izquierda.

ColumnReverse, lo mismo que column pero con la diferencia que los elementos se colocarán de abajo a arriba.

Por defecto, todos nuestros FlexLayout tienen como valor predeterminado Row.

direction
Direction

Otra propiedad muy interesante es Wrap. Usando está propiedad podemos organizar la ubicación de los componentes, por defecto, se apilan todos en una única fila de forma ordenada una detrás de otro. Si queremos cambiar ese comportamiento podemos establecerlo con los siguientes valores que tenemos:

NoWrap, todos los elementos se colocan en la misma línea.

Wrap, todos los elementos se colocan en múltiples líneas de arriba a abajo.

Reverse, todos los elementos se colocan en múltiples líneas de abajo a arriba.

Por defecto, todos nuestros FlexLayout tienen como valor predeterminado NoWrap.

Wrap
Wrap

JustifyContent

Está propiedad organiza los elementos en el eje principal. Si queremos cambiar ese comportamiento podemos establecerlo con los siguientes valores que tenemos:

Start, todos los elementos se agruparan al inicio del eje principal.

Center, todos los elementos se agruparan en el centro del eje principal.

End, todos los elementos se agruparan en el final del eje principal.

JustifyContent
JustifyContent

SpaceBetween, todos los elementos tienen el mismo espacio entre cada elemento.

SpaceAround, los elementos mantiene el mismo espacio entre cada elemento. Comienza con una unidad de espacio para los bordes y dos unidades respectivas a otros elementos en el contenedor.

SpaceEvenly, todos los elementos se distribuyen manteniendo el mismo espacio entre elementos y los bordes.

Por defecto, todos nuestros FlexLayout tienen como valor predeterminado Start.

JustifyContentSpace
justifyContent space

AlignItems

Similar a la anterior, la principal diferencia es que está propiedad definimos el comportamiento del eje transversal. Los valores que tenemos son:

Start Center End Stretch, está propiedad extiende todo el elemento de manera que se ajuste a la pantalla.

El resto de opciones agruparan los elementos al inicio, al centro y al final eje transversal. Es lo mismo que describimos arriba pero cambiando de eje.

En el código subido a github tenéis una View llamada login, podéis probar estás propiedades (AlignItems y JustifyContent) para ver y comprender mejor su funcionamiento.

    <FlexLayout
        AlignItems="Center"
        Direction="Column"
        JustifyContent="SpaceEvenly">
        <Image
            Aspect="AspectFit"
            HeightRequest="125"
            Source="xamarin"
            WidthRequest="125" />
        <StackLayout WidthRequest="280">
            <Entry Placeholder="Email" />
            <Entry IsPassword="True" Placeholder="Password" />
        </StackLayout>
        <Grid>
            <Button
                BackgroundColor="Blue"
                CornerRadius="20"
                Text="Login"
                TextColor="White"
                WidthRequest="280" />
        </Grid>
    </FlexLayout>
AlignItems
AlignItems

AlignContent

Está propiedad solo funciona cuando hacemos wrap a nuestro contenedor. Gracias a AlignContent podemos controlar el espacio adicional en el eje transversal. Los valores que tenemos son:

Start Center End Stretch SpaceBetween SpaceAround SpaceEvenly

Por defecto, todos nuestros FlexLayout tienen como valor predeterminado Stretch. El resto de opciones son iguales que las propiedades que mencionamos en JustifyContent a excepción de stretch que no está disponible en JustifyContent pero que vimos más arriba con AlignItems.

<Style x:Key="FlexLayoutStyle" TargetType="FlexLayout"> 
    <Setter Property="Direction" Value="Row" />  
    <Setter Property="Wrap" Value="Wrap" />
    <Setter Property="AlignItems" Value="Stretch" />
    <Setter Property="AlignContent" Value="Center" />
</Style> 

<Style TargetType="Grid">
    <Setter Property="HeightRequest" Value="100" />
</Style>

<FlexLayout Style="{StaticResource FlexLayoutStyle}">
	<Grid
		BackgroundColor="Red"
                FlexLayout.Basis="20%"
                FlexLayout.Grow="0">
                <Label Text="20%" />
        </Grid>
        <Grid
                BackgroundColor="DarkViolet"
                FlexLayout.Basis="25%"
                FlexLayout.Grow="0">
                <Label Text="25%" />
        </Grid>
        <Grid
                BackgroundColor="Red"
                FlexLayout.Basis="20%"
                FlexLayout.Grow="0">
                <Label Text="20%" />
         </Grid>
         <Grid
                BackgroundColor="DarkViolet"
                FlexLayout.Basis="25%"
                FlexLayout.Grow="0">
                <Label Text="25%" />
         </Grid>
         <Grid BackgroundColor="Green" FlexLayout.Grow="1">
                <Label Text="Auto" />
         </Grid>
          
         <Grid BackgroundColor="Green" FlexLayout.Grow="1">
                <Label Text="Grow 1" />
         </Grid>
         <Grid BackgroundColor="Aquamarine" FlexLayout.Grow="2">
	         <Label Text="Grow 2" />
	 </Grid>
         <Grid BackgroundColor="Brown" FlexLayout.Grow="1">
		  <Label Text="Grow 1" />
         </Grid>
</FlexLayout>

En el repositorio que he tengo en github, hay una vista llamada AlignContentView donde podrás probar está propiedad.

Propiedades de cada elemento

No soló podemos cambiar el comportamiento de nuestro layout con sus propiedades principales, también podemos adaptar las propiedades de cada elemento que tengamos en nuestro contenedor.

Para ello, disponemos de FlexLayout.Grow y FlexLayout.Basis.

FlexLayout.Grow

Está propiedad acepta valores desde cero a cualquier valor numérico positivo. Por defecto el valor es cero. Con este valor le indicamos a nuestro elemento que no debe estirarse para ajustarse al espacio sobrante.

Si en cambio queremos que nuestro elemento ocupe toda la pantalla le estableceremos el valor a 1 y el elemento pasará a ocupar todo el espacio.

Si tenemos dos o más elementos, los valores que se le asigna indica siempre que proporción va a ocupar nuestro elemento respecto a los demás. Veamos un pequeño ejemplo.

Supongamos que tenemos 3 grid y quiero que el segundo elemento sea el doble de tamaño que el primer elemento y el tercer elemento. Mi código sería el siguiente:

<Style x:Key="FlexLayoutStyle" TargetType="FlexLayout"> 
    <Setter Property="Direction" Value="Row" />  
    <Setter Property="Wrap" Value="Wrap" />
    <Setter Property="AlignItems" Value="Stretch" />
    <Setter Property="AlignContent" Value="Center" />
</Style> 

<Style TargetType="Grid">
    <Setter Property="HeightRequest" Value="100" />
</Style>

<FlexLayout Style="{StaticResource FlexLayoutStyle}">
         <Grid BackgroundColor="Green" FlexLayout.Grow="1">
                <Label Text="Grow 1" />
         </Grid>
         <Grid BackgroundColor="Aquamarine" FlexLayout.Grow="2">
	         <Label Text="Grow 2" />
	 </Grid>
         <Grid BackgroundColor="Brown" FlexLayout.Grow="1">
		  <Label Text="Grow 1" />
         </Grid>
</FlexLayout>
FlexLayout.Grow
FlexLayout.Grow

Tanto el primer como tercer elemento el valor del FlexLayout.Grow será uno y del segundo elemento será dos. Con esto le estamos indicando que el segundo elemento será el doble respecto a los demás elementos.

Si solo tenemos un elemento, con indicarle el valor uno es más que suficiente puesto que al ser el único elemento se va a estilar toda la pantalla.

FlexLayout.Basis

Está propiedad define el tamaño que tendrá un elemento antes de que se distribuya el espacio sobrante. Al igual que FlexLayout.Grow, los valores que se le asigna indica siempre que proporción va a ocupar nuestro elemento. En este caso se le asigna con un porcentaje, aunque también acepta unidades de valor. Tenemos otra opción y es usar palabras reservadas como Auto. Está propiedad nos da un control más complemento respecto a la propiedad FlexLayout.Grow sobre el tamaño de cada elemento del hijo del contenedor.

<Style x:Key="FlexLayoutStyle" TargetType="FlexLayout"> 
    <Setter Property="Direction" Value="Row" />  
    <Setter Property="Wrap" Value="Wrap" />
    <Setter Property="AlignItems" Value="Stretch" />
    <Setter Property="AlignContent" Value="Center" />
</Style> 

<Style TargetType="Grid">
    <Setter Property="HeightRequest" Value="100" />
</Style>

<FlexLayout Style="{StaticResource FlexLayoutStyle}">
	<Grid BackgroundColor="Red"
              FlexLayout.Basis="20%"
              FlexLayout.Grow="0">
		<Label Text="20%" />
        </Grid>
        <Grid BackgroundColor="DarkViolet"
              FlexLayout.Basis="25%"
              FlexLayout.Grow="0">
	        <Label Text="25%" />
        </Grid>
        <Grid BackgroundColor="Red"
              FlexLayout.Basis="20%"
              FlexLayout.Grow="0">
	         <Label Text="20%" />
        </Grid>
        <Grid BackgroundColor="DarkViolet"
              FlexLayout.Basis="25%"
              FlexLayout.Grow="0">
	         <Label Text="25%" />
        </Grid>
</FlexLayout>
FlexLayout.Basis
FlexLayout.Basis

Reto

  1. Replicar con un Grid, un StackLayout y un FlexLayout el siguiente layout:
Reto
Reto
  1. Replicar las siguientes imágenes que está en el repositorio antes de ver el código.

Conclusiones

Mi impresión con este layout es que tenemos unas propiedades similares a la de un Grid o de un StackLayout pero con mucho más poder. La flexibilidad de colocar nuestros elementos visuales que nos da a día de hoy no la tenemos con ningún otro layout.

Lo que más destaco de este layout es la gran ayuda que tenemos para acomodar y alinear nuestras vistas dentro de una pantalla, envolverlos si hubiera muchas vistas/elementos para que quepan en una sola fila o columna y sobre todo las opciones que tenemos para adaptarse a cualquier tipo de tamaño de pantalla y orientación del dispositivo.

Ver proyecto

Por último, no olvides seguirme en GitHub para ver el código de los proyectos que voy subiendo :)

De momento esto es todo. Happy coding Xamarianos.

Más información

Layouts