Xamarin.Forms RelativeLayout

Download SampleDescargar el ejemplo

Xamarin.Forms RelativeLayout

Un RelativeLayout sirve para colocar y ajustar el tamaño de los elementos secundarios en relación con las propiedades del diseño o los elementos del mismo nivel. Esto permite crear interfaces de usuario que se escalan proporcionalmente entre tamaños de dispositivo. Además, a diferencia de otras clases de diseño, RelativeLayout es capaz de colocar elementos secundarios para que se superpongan.

La clase RelativeLayout define las propiedades siguientes:

  • XConstraint, de tipo Constraint, que es una propiedad adjunta que representa la restricción en la posición X del elemento secundario.
  • YConstraint, de tipo Constraint, que es una propiedad adjunta que representa la restricción en la posición Y del elemento secundario.
  • WidthConstraint, de tipo Constraint, que es una propiedad adjunta que representa la restricción en el ancho del elemento secundario.
  • HeightConstraint, de tipo Constraint, que es una propiedad adjunta que representa la restricción en el alto del elemento secundario.
  • BoundsConstraint, de tipo BoundsConstraint, que es una propiedad adjunta que representa la restricción en la posición y el tamaño del elemento secundario. Esta propiedad no se puede consumir fácilmente desde XAML.

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos, y se les puede aplicar estilos. Para obtener más información sobre las propiedades adjuntas, consulte Xamarin.FormsPropiedades asociadas.

Nota:

También se puede especificar el ancho y el alto de un elemento secundario en un RelativeLayout a través de las propiedades WidthRequest y HeightRequest del elemento secundario, en lugar de hacerlo en las propiedades adjuntas WidthConstraint y HeightConstraint.

La clase RelativeLayout deriva de la clase Layout<T>, que define una propiedad Children de tipo IList<T>. La propiedad Children es ContentProperty de la clase Layout<T> y, por tanto, no es necesario establecerla explícitamente desde XAML.

Sugerencia

Evite el uso de un RelativeLayout siempre que sea posible. Como resultado, la CPU tendrá que realizar mucho más trabajo.

Restricciones

Dentro de un RelativeLayout, la posición y el tamaño de los elementos secundarios se especifican como restricciones mediante valores absolutos o relativos. Cuando no se especifican restricciones, un elemento secundario se colocará en la esquina superior izquierda del diseño.

En la tabla siguiente se muestra cómo especificar restricciones en XAML y C#:

XAML C#
Valores absolutos Las restricciones absolutas se especifican estableciendo las propiedades adjuntas RelativeLayout en valores double. Las restricciones absolutas se especifican mediante el método Constraint.Constant o mediante la sobrecarga Children.Add que requiere un argumento Func<Rectangle>.
Valores relativos Las restricciones relativas se especifican estableciendo las propiedades adjuntas RelativeLayout en objetos Constraint devueltos por la extensión de marcado ConstraintExpression. Las restricciones relativas se especifican mediante objetos Constraint devueltos por métodos de la clase Constraint.

Para obtener más información sobre cómo especificar restricciones mediante valores absolutos, consulte Posicionamiento y ajuste de tamaño absolutos. Para obtener más información sobre cómo especificar restricciones mediante valores relativos, consulte Posicionamiento y ajuste de tamaño relativos.

En C#, los elementos secundarios se pueden agregar a RelativeLayout mediante tres sobrecargas Add. La primera sobrecarga requiere que un Expression<Func<Rectangle>> especifique la posición y el tamaño de un elemento secundario. La segunda sobrecarga requiere objetos Expression<Func<double>> opcionales para los argumentos x, y, width y height. La tercera sobrecarga requiere objetos Constraint opcionales para los argumentos x, y, width y height.

Es posible cambiar la posición y el tamaño de un elemento secundario de un RelativeLayout con los métodos SetXConstraint, SetYConstraint, SetWidthConstraint y SetHeightConstraint. El primer argumento para cada uno de estos métodos es el elemento secundario y el segundo, un objeto Constraint. Además, el método SetBoundsConstraint también se puede usar para cambiar la posición y el tamaño de un elemento secundario. El primer argumento para este método es el elemento secundario; el segundo es un objeto BoundsConstraint.

Posición absoluta y ajuste de tamaño

Un RelativeLayout puede colocar y ajustar el tamaño de los elementos secundarios mediante valores absolutos, especificados en unidades independientes del dispositivo, que definen explícitamente dónde deben colocarse los elementos secundarios en el diseño. Esto se logra agregando elementos secundarios a la colección Children de un RelativeLayout, y estableciendo las propiedades adjuntas XConstraint, YConstraint, WidthConstraint y HeightConstraint en cada elemento secundario a valores absolutos de posición o tamaño.

Advertencia

El uso de valores absolutos para colocar y ajustar el tamaño de los elementos secundarios puede ser problemático, ya que los diferentes dispositivos tienen diferentes tamaños de pantalla y resoluciones. Por lo tanto, las coordenadas del centro de la pantalla en un dispositivo pueden desplazarse en otros dispositivos.

En el código XAML siguiente se muestra un RelativeLayout cuyos elementos secundarios se colocan con valores absolutos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="RelativeLayoutDemos.Views.StylishHeaderDemoPage"
             Title="Stylish header demo">
    <RelativeLayout Margin="20">
        <BoxView Color="Silver"
                 RelativeLayout.XConstraint="0"
                 RelativeLayout.YConstraint="10"
                 RelativeLayout.WidthConstraint="200"
                 RelativeLayout.HeightConstraint="5" />
        <BoxView Color="Silver"
                 RelativeLayout.XConstraint="0"
                 RelativeLayout.YConstraint="20"
                 RelativeLayout.WidthConstraint="200"
                 RelativeLayout.HeightConstraint="5" />
        <BoxView Color="Silver"
                 RelativeLayout.XConstraint="10"
                 RelativeLayout.YConstraint="0"
                 RelativeLayout.WidthConstraint="5"
                 RelativeLayout.HeightConstraint="65" />
        <BoxView Color="Silver"
                 RelativeLayout.XConstraint="20"
                 RelativeLayout.YConstraint="0"
                 RelativeLayout.WidthConstraint="5"
                 RelativeLayout.HeightConstraint="65" />
        <Label Text="Stylish header"
               FontSize="24"
               RelativeLayout.XConstraint="30"
               RelativeLayout.YConstraint="25" />
    </RelativeLayout>
</ContentPage>

En este ejemplo, la posición de cada objeto BoxView se define mediante los valores especificados en las propiedades adjuntas XConstraint y YConstraint. El tamaño de cada BoxView se define mediante los valores especificados en las propiedades adjuntas WidthConstraint y HeightConstraint. La posición del objeto Label también se define mediante los valores especificados en las propiedades adjuntas XConstraint y YConstraint. Sin embargo, los valores de tamaño no se especifican para Label y, por tanto, no tiene restricciones y se dimensiona por sí misma. En todos los casos, los valores absolutos representan unidades independientes del dispositivo.

En las capturas de pantalla siguientes se muestra el diseño resultante:

Children placed in a RelativeLayout using absolute values

El código de C# equivalente se muestra a continuación:

public class StylishHeaderDemoPageCS : ContentPage
{
    public StylishHeaderDemoPageCS()
    {
        RelativeLayout relativeLayout = new RelativeLayout
        {
            Margin = new Thickness(20)
        };

        relativeLayout.Children.Add(new BoxView
        {
            Color = Color.Silver
        }, () => new Rectangle(0, 10, 200, 5));

        relativeLayout.Children.Add(new BoxView
        {
            Color = Color.Silver
        }, () => new Rectangle(0, 20, 200, 5));

        relativeLayout.Children.Add(new BoxView
        {
            Color = Color.Silver
        }, () => new Rectangle(10, 0, 5, 65));

        relativeLayout.Children.Add(new BoxView
        {
            Color = Color.Silver
        }, () => new Rectangle(20, 0, 5, 65));

        relativeLayout.Children.Add(new Label
        {
            Text = "Stylish Header",
            FontSize = 24
        }, Constraint.Constant(30), Constraint.Constant(25));

        Title = "Stylish header demo";
        Content = relativeLayout;
    }
}

En este ejemplo, se agregan objetos BoxView a RelativeLayout mediante una sobrecarga Add que requiere que un Expression<Func<Rectangle>> especifique la posición y el tamaño de cada elemento secundario. La posición de Label se define mediante una sobrecarga Add que requiere objetos Constraint opcionales, en este caso creados por el método Constraint.Constant.

Nota:

Un RelativeLayout que usa valores absolutos puede colocar y ajustar los elementos secundarios para que no se ajusten a los límites del diseño.

Posicionamiento y ajuste de tamaño relativos

Un RelativeLayout puede colocar y ajustar el tamaño de los elementos secundarios mediante valores relativos a las propiedades del diseño o elementos del mismo nivel. Esto se logra agregando elementos secundarios a la colección Children del RelativeLayout, y estableciendo las propiedades adjuntas XConstraint, YConstraint, WidthConstraint y HeightConstraint en cada elemento secundario a valores relativos mediante objetos Constraint.

Las restricciones pueden ser una constante, relativa a un elemento primario o a un elemento del mismo nivel. El tipo de restricción se representa mediante la enumeración ConstraintType, que define los siguientes miembros:

  • RelativeToParent, que indica una restricción relativa a un elemento primario.
  • RelativeToView, que indica una restricción relativa a una vista (o del mismo nivel).
  • Constant, que indica una restricción constante.

Extensión de marcado de restricciones

En XAML, la extensión de marcado ConstraintExpression puede crear un objeto Constraint. Esta extensión de marcado se usa normalmente para relacionar la posición y el tamaño de un elemento secundario dentro de un RelativeLayout a su elemento primario o a un elemento del mismo nivel.

La clase ConstraintExpression define las propiedades siguientes:

  • Constant, de tipo double, que representa el valor constante de restricción.
  • ElementName, de tipo string, que representa el nombre de un elemento de origen con el que debe calcularse la restricción.
  • Factor, de tipo double, que representa el factor por el que se escala una dimensión restringida, en relación con el elemento de origen. Esta propiedad tiene como valor predeterminado 1.
  • Property, de tipo string, que representa el nombre de la propiedad en el elemento de origen que se va a usar en el cálculo de restricciones.
  • Type, de tipo ConstraintType, que representa el tipo de la restricción.

Para más información sobre las extensiones de marcado de Xamarin.Forms, vea Extensiones de marcado para el lenguaje XAML.

En el código XAML siguiente se muestra un RelativeLayout cuyos elementos secundarios están restringidos por la extensión de marcado ConstraintExpression:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="RelativeLayoutDemos.Views.RelativePositioningAndSizingDemoPage"
             Title="RelativeLayout demo">
    <RelativeLayout>
        <BoxView Color="Red"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}" />
        <BoxView Color="Green"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Constant=-40}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}" />
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Constant=-40}" />
        <BoxView Color="Yellow"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Constant=-40}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Constant=-40}" />

        <!-- Centered and 1/3 width and height of parent -->
        <BoxView x:Name="oneThird"
                 Color="Silver"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.33}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.33}"
                 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.33}"
                 RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.33}" />

        <!-- 1/3 width and height of previous -->
        <BoxView Color="Black"
                 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, ElementName=oneThird, Property=X}"
                 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=oneThird, Property=Y}"
                 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=oneThird, Property=Width, Factor=0.33}"
                 RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=oneThird, Property=Height, Factor=0.33}" />
    </RelativeLayout>
</ContentPage>

En este ejemplo, la posición de cada objeto BoxView se define estableciendo las propiedades adjuntas XConstraint y YConstraint. La primera BoxView tiene sus propiedades adjuntas XConstraint y YConstraint establecidas en constantes, que son valores absolutos. Todos los objetos BoxView restantes tienen su posición establecida mediante al menos un valor relativo. Por ejemplo, el objeto BoxView amarillo establece la propiedad adjunta XConstraint en el ancho de su elemento primario (RelativeLayout) menos 40. Del mismo modo, BoxView establece la propiedad adjunta YConstraint en el alto de su elemento primario menos 40. Así se garantiza que el objeto BoxView amarillo aparezca en la esquina inferior derecha de la pantalla.

Nota:

Los objetos BoxView que no especifican ningún tamaño se ajustan automáticamente a 40x40 por Xamarin.Forms.

El objeto BoxView plateado denominado oneThird se coloca centralmente, en relación con su elemento primario. También tiene un tamaño relativo a su elemento primario, siendo un tercio de su ancho y alto. Esto se logra estableciendo las propiedades adjuntas XConstraint y WidthConstraint en el ancho del elemento primario (RelativeLayout), multiplicado por 0,33. De forma similar, las propiedades adjuntas YConstraint y HeightConstraint se establecen en el alto del elemento primario, multiplicado por 0,33.

El objeto BoxView negro se coloca y se ajusta al tamaño con respecto a oneThirdBoxView. Esto se logra estableciendo sus propiedades adjuntas XConstraint y YConstraint en los valores X y Y, respectivamente, del elemento del mismo nivel. Del mismo modo, su tamaño se establece en un tercio del ancho y alto de su elemento del mismo nivel. Esto se logra estableciendo sus propiedades adjuntas WidthConstraint y HeightConstraint en los valores Width y Height del elemento del mismo nivel, respectivamente, que se multiplican por 0,33.

En la captura de pantalla siguiente se muestra el diseño resultante:

Children placed in a RelativeLayout using relative values

Objetos de restricción

La clase Constraint define los siguientes métodos estáticos públicos, que devuelven objetos Constraint:

  • Constant, que restringe un elemento secundario a un tamaño especificado con double.
  • FromExpression, que restringe un elemento secundario mediante una expresión lambda.
  • RelativeToParent, que restringe un elemento secundario con respecto al tamaño de su elemento primario.
  • RelativeToView, que restringe un elemento secundario con respecto al tamaño de una vista.

Además, la clase BoundsConstraint define un único método, FromExpression, que devuelve un BoundsConstraint que restringe la posición y el tamaño de un elemento secundario con Expression<Func<Rectangle>>. Este método se puede usar para establecer la propiedad adjunta BoundsConstraint.

El siguiente código de C# muestra un RelativeLayout cuyos elementos secundarios están restringidos por objetos Constraint:

public class RelativePositioningAndSizingDemoPageCS : ContentPage
{
    public RelativePositioningAndSizingDemoPageCS()
    {
        RelativeLayout relativeLayout = new RelativeLayout();

        // Four BoxView's
        relativeLayout.Children.Add(
            new BoxView { Color = Color.Red },
            Constraint.Constant(0),
            Constraint.Constant(0));

        relativeLayout.Children.Add(
            new BoxView { Color = Color.Green },
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width - 40;
            }), Constraint.Constant(0));

        relativeLayout.Children.Add(
            new BoxView { Color = Color.Blue },
            Constraint.Constant(0),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height - 40;
            }));

        relativeLayout.Children.Add(
            new BoxView { Color = Color.Yellow },
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width - 40;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height - 40;
            }));

        // Centered and 1/3 width and height of parent
        BoxView silverBoxView = new BoxView { Color = Color.Silver };
        relativeLayout.Children.Add(
            silverBoxView,
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width * 0.33;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height * 0.33;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width * 0.33;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height * 0.33;
            }));

        // 1/3 width and height of previous
        relativeLayout.Children.Add(
            new BoxView { Color = Color.Black },
            Constraint.RelativeToView(silverBoxView, (parent, sibling) =>
            {
                return sibling.X;
            }),
            Constraint.RelativeToView(silverBoxView, (parent, sibling) =>
            {
                return sibling.Y;
            }),
            Constraint.RelativeToView(silverBoxView, (parent, sibling) =>
            {
                return sibling.Width * 0.33;
            }),
            Constraint.RelativeToView(silverBoxView, (parent, sibling) =>
            {
                return sibling.Height * 0.33;
            }));

        Title = "RelativeLayout demo";
        Content = relativeLayout;
    }
}

En este ejemplo, se agregan elementos secundarios a RelativeLayout mediante la sobrecarga Add que requiere un objeto Constraint opcional para los argumentos x, y, width y height.

Nota:

Un RelativeLayout que usa valores relativos puede colocar y ajustar los elementos secundarios para que no se ajusten a los límites del diseño.