rraallvv
rraallvv

Reputation: 2933

Why won't these constraints in a RelativeLayout work on a Xamarin Forms project?

The layout is as follows:

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:Test.Views" x:Class="Test.Views.MainPage">
    <StackLayout VerticalOptions="FillAndExpand">
        <BoxView Color="Yellow" HeightRequest="25" VerticalOptions="Start"></BoxView>
        <RelativeLayout x:Name="mainView" BackgroundColor="Red" VerticalOptions="StartAndExpand">
            <BoxView x:Name="boxA" Color="Blue" WidthRequest="50" HeightRequest="50"
                RelativeLayout.XConstraint="{Binding BoxAXConstraint}"
                RelativeLayout.YConstraint="{Binding BoxAYConstraint}">
            </BoxView>
            <BoxView x:Name="boxB" Color="Green" WidthRequest="50" HeightRequest="50"
                RelativeLayout.XConstraint="{Binding BoxBXConstraint}"
                RelativeLayout.YConstraint="{Binding BoxBYConstraint}">
            </BoxView>
        </RelativeLayout>
    </StackLayout>
</ContentPage>

I couldn't find a way to specify the bottom right corner in a relative layout in XAML, that's why I'm binding those constraints to properties in the code-behind like this:

public partial class MainPage : ContentPage
{
    public Constraint BoxAXConstraint { get; set; }
    public Constraint BoxAYConstraint { get; set; }
    public Constraint BoxBXConstraint { get; set; }
    public Constraint BoxBYConstraint { get; set; }

    public MainPage()
    {
        InitializeComponent();

        BoxAXConstraint = Constraint.RelativeToParent(parent => mainView.Width - boxA.WidthRequest);
        BoxAYConstraint = Constraint.RelativeToParent(parent => 0);
        BoxBXConstraint = Constraint.RelativeToParent(parent => mainView.Width - boxB.WidthRequest);
        BoxBYConstraint = Constraint.RelativeToParent(parent => mainView.Height - boxB.HeightRequest);

        BindingContext = this;
    }
}

This is a test project that reproduces the issue on both Android and iOS.

enter image description here enter image description here

Upvotes: 0

Views: 584

Answers (1)

DavidS
DavidS

Reputation: 2934

RelativeLayout has limitations on what can be expressed in XAML - you can't reference layout properties of two different elements in the same constraint, for instance. You can definitely express more in C#. In this case, you should be able to do things almost equivalently in XAML:

        <BoxView x:Name="boxB" Color="Green" WidthRequest="50" HeightRequest="50"
            RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
        Property=Width,Factor=1,Constant=-50}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
        Property=Height,Factor=1,Constant=-50}">
        </BoxView>

The downside of the XAML approach is that if you change the WidthRequest or HeightRequest, you also need to change the constraints, whereas in the C# version, the changes are automatically taken into account because of the way the constraints are defined.

You could look into AbsoluteLayout, which (unlike RelativeLayout) attempts to keep elements on the screen. So you can position a child of an AbsoluteLayout to be in the bottom right corner fairly easily in XAML:

AbsoluteLayout.LayoutBounds="1,1,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional"

Upvotes: 1

Related Questions