Demystifying Xamarin Forms AbsoluteLayout and RelativeLayout positioning.

In my last post you may have noticed that I used an AbsoluteLayout to position the content of my view so that it always appears 5% from the top of the screen. The intention is to allow for different device screen sizes so that the gap from the top of the screen is relative to the height of the screen. There is a lot more work that I need to do with this yet and I have been exploring the possibilities available to me.

Relative positioning in Xamarin Forms is one of the most bewildering aspects that I have encountered. There are numerous options we can use and some don’t always yield the results we might expect.

Let’s take a simple example and try to position a BoxView 25% from the top of the screen and 25% from the left of the screen, with a height 25% the size of the screen and the width 25% the width of the screen. Easy right!

I will show you 4 different ways you can achieve this.

Grid

We can simply define a Grid with 4 rows and columns with the Height and Width set to “*” so that they are equally proportioned. We can then position the BoxView in the second row and column like this:

    <Grid RowSpacing="0" ColumnSpacing="0">
      <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>

      <BoxView Grid.Row="1" Grid.Column="1" BackgroundColor="Red" />
    </Grid>

This results look like this:

Screen Shot 2015-05-05 at 22.01.00

Well that wasn’t too hard, but do I really want to define all those rows and columns and split the screen up like that just to position my BoxView. Supposing I wanted it 10% from the top. I’d have to define 10 rows!! Alternatively we can use the AbsoluteLayout.

AbsoluteLayout

This allows us to specify the proportional position and size using LayoutBounds and LayoutFlags. The LayoutFlags allow us to specify whether we want the position, the size, or both to be proportional to the AbsoluteLayout. The LayoutBounds takes 4 values. The first 2 specify the x and y position and the last 2 specify the width and height. If we have specified any of these as proportional using the LayoutFlags then the values should be expressed as a proportional value between 0 and 1. Confusing right!

It certainly took me a while to get to grips with this and as you will see it can also be misleading. I found the Xamarin Forms documentation to be somewhat lacking in content and clarity, but it’s still worth checking out here. Charles Petzold has also written a chatper on AbsoluteLayout for the forthcoming Xamarin Forms book which is worth checking out here.

Let’s have a go at this then. I will extend my previous example and add another BoxView using an AbsoluteLayout. I will set the LayoutFlags to All as I want to have both proportional position and size. I will specify that I want the BoxView x position to be 25% the width of the AbsoluteLayout and the y position to be 25% of its height. I will also specifiy the Width and Height to be 25% the size of the AbsoluteLayout. To do this all I need to do is set each LayoutBound value to 0.25. Here’s the Xaml for this:

    <AbsoluteLayout Opacity="0.75">
      <BoxView Color="Yellow"
               AbsoluteLayout.LayoutBounds="0.25,0.25,0.25,0.25"
               AbsoluteLayout.LayoutFlags="All" />
    </AbsoluteLayout>

I have also set the opacity to 0.75 so that I can see this over the top of my existing Red BoxView, which I know is positioned correctly.

Let’s take a look at the results.

Screen Shot 2015-05-05 at 22.00.23

Oh dear! That’s not what I expected. The BoxView is offset so that it falls short of the correct x and y positions. Why has this happened?

It took me a while to wrap my head around this but essentially the AbsoluteLayout also takes into account the size of the control when calculating the relative x and y position. In other words it is 25% of the AbsoluteLayout less the size of the control. Why would it do this? That’s a good question. One thing I do know is that this means that I can never specify the control to be off the screen. What would you expect if I set the x and y position to be 1, which is the full width and height of the screen. Here’s the result:

    <AbsoluteLayout Opacity="0.75">
      <BoxView Color="Yellow"
               AbsoluteLayout.LayoutBounds="1,1,0.25,0.25"
               AbsoluteLayout.LayoutFlags="All" />
    </AbsoluteLayout>

Screen Shot 2015-05-05 at 22.12.48

As you can see the x and y position of the BoxView is now it’s bottom, right corner and it appears flush to the bottom right of the AbsoluteLayout. So the AbsoluteLayout takes into account the size of the control so that it always fits the screen. In some cases this is perhaps exactly what you might want to achieve with proportional positioning and sizing, but in this case and may others it clearly isn’t. How do we fix this? Well you could calculate what the correct proportional percentage should be, in this case 33% and define it like this:

    <AbsoluteLayout Opacity="0.75">
      <BoxView Color="Yellow"
               AbsoluteLayout.LayoutBounds="0.333,0.333,0.25,0.25"
               AbsoluteLayout.LayoutFlags="All" />
    </AbsoluteLayout>

Screen Shot 2015-05-05 at 22.20.34

Spot on! But do I really want to have to do this calculation to work this out? I hope not. Well, there is another ‘trick’ that in some cases works really well. If instead we set the y position to be 1, as we have just seen we know that this means the bottom of the screen. Then place the BoxView inside a StackLayout and specify that to be 75% the height of the AbsoluteLayout like is:

    <AbsoluteLayout Opacity="0.75">
        <StackLayout AbsoluteLayout.LayoutBounds="0.25,1,0.25,0.75"
                     AbsoluteLayout.LayoutFlags="All">
            <BoxView Color="Yellow" />
        </StackLayout>
    </AbsoluteLayout>

We get the following results.

Screen Shot 2015-05-05 at 22.33.37

Humm, that’s interesting. I’ve kind of got the y position right, but the x and size is a bit screwy. A single BoxView isn’t really a great example here. If however we had a StackLayout with some ‘stacked’ content that we wanted to be positioned 25% from the top of the screen then we can use this trick to acheive this. Here’s a better example:

    <AbsoluteLayout>
      <StackLayout AbsoluteLayout.LayoutBounds="0,1,1,0.75"
                   AbsoluteLayout.LayoutFlags="All"
                   BackgroundColor="#7E808080">
        <Label Text="Lorem ipsum dolor sit amet" BackgroundColor="Teal" />
        <Label VerticalOptions="CenterAndExpand" Text="Lorem ipsum dolor sit amet, nobis doctus commodo eam no, ius ad persecuti temporibus. Homero impetus reprehendunt mel cu, mollis tibique principes per ea. Sale nostro eruditi no pro, mei unum saperet ne, te modo latine usu. Ius verear maiestatis an. Mel cu iriure officiis, ne eam impetus torquatos persecuti. Audire nusquam adversarium te quo." />
      </StackLayout>
    </AbsoluteLayout>

Screen Shot 2015-05-05 at 22.46.30

As you can see the StackLayout is position 25% from the top, or to be more precise 75% from the bottom. The Label is set to CenterAndExpand so that the text is centered in the remaining space. This is the technique I used in my previous post and is very useful in these cases. However, I have now discovered a better way using the RelativeLayout.

RelativeLayout

The RelativeLayout allows us to define ‘constraints’ against the Width, Height, X and Y properties of a control, which are relative to either its parent or another control. Again the Xamarin Forms documentation is very poor for this and I had to go scratching around to find examples. Xamarin really do need to improve on their documentation.

I’d kind of discarded it initially because I thought that the constraint had to be an absolute fixed constant value, until I discovered the Factor property. This curious property lets you specify a percentage value (or Factor) against the property of another control to calcuate the value for the constraint.

Humm, this sounds interesting. Let’s give it a try. Here’s the Xaml which defines constraints for Width, Height, X and Y which are all 25% relative to its parent using Factor=0.25.

    <RelativeLayout>
      <BoxView Color="Aqua"
               RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.25}"
               RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.25}"
               RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.25}"
               RelativeLayout.YConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.25}"
               />
    </RelativeLayout>

As you can see the Attached constraint property looks a bit weird, but is perfectly readable and concise.

Let’s take a look at the results:

Screen Shot 2015-05-05 at 22.58.13

Yes! That’s exactly what I wanted to see!

I wonder if we can perform the same trick with a StackLayout. If we define a Height Contraint of 75% and a Y Contraint of 25% like this:

    <RelativeLayout>
      <StackLayout RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.75}"
                   RelativeLayout.YConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.25}"
                   BackgroundColor="Gray">
        <Label Text="Lorem ipsum dolor sit amet" BackgroundColor="Yellow" />
        <Label VerticalOptions="CenterAndExpand" Text="Lorem ipsum dolor sit amet, nobis doctus commodo eam no, ius ad persecuti temporibus. Homero impetus reprehendunt mel cu, mollis tibique principes per ea. Sale nostro eruditi no pro, mei unum saperet ne, te modo latine usu. Ius verear maiestatis an. Mel cu iriure officiis, ne eam impetus torquatos persecuti. Audire nusquam adversarium te quo." />
      </StackLayout>
    </RelativeLayout>

We get this result.

Screen Shot 2015-05-05 at 23.22.34

Excellent! This looks a much simpler and better way to define this kind of relative positioning. I suppose in the end the answer was in the name RelativeLayout, Doh!

Whichever technique you use really depends on your scenario. There are a bewildering array of options available with both Absolute and Relative Layout, so I suggest you experiment a bit to get the best results.

5 thoughts on “Demystifying Xamarin Forms AbsoluteLayout and RelativeLayout positioning.

  1. Thank you for this. I have really been scratching my head with some of this functionality, but this clears things up significantly.

    Like

      1. Wanted to create a page header consists of few labels and image buttons and this pageheader should be part of all the pages in my application. Could you give some light on creating such apage header in XAML

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s