left-icon

Xamarin.Forms for macOS Succinctly®
by Alessandro Del Sole

Previous
Chapter

of
A
A
A

CHAPTER 4

Organizing the UI with Layouts

Organizing the UI with Layouts


Mobile devices such as phones, tablets, and laptops have different screen sizes and form factors. They also support both landscape and portrait orientations. Therefore, the user interface in mobile apps must dynamically adapt to the system, screen, and device so that visual elements can be automatically resized or rearranged based on the form factor and device orientation. In Xamarin.Forms, this is accomplished with layouts, which is the topic of this chapter.

Understanding the concept of layout

One of the goals of Xamarin.Forms is to provide the ability to create dynamic interfaces that can be rearranged according to the user’s preferences or to the device and screen size. Because of this, controls in mobile apps that you build with Xamarin should not have a fixed size or position on the UI, except in a very limited number of scenarios. To make this possible, Xamarin.Forms controls are arranged within special containers, known as layouts. Layouts are classes that allow for arranging visual elements in the UI, and Xamarin.Forms provides many of them.

In this chapter, you’ll learn about available layouts and how to use them to arrange controls. The most important thing you have to keep in mind is that controls in Xamarin.Forms have a hierarchical structure; therefore, you can nest multiple panels to create complex user experiences. Table 2 summarizes available layouts. Then, in the next sections, you’ll learn about them in more detail.

Table 2: Layouts in Xamarin.Forms

Layout

Description

StackLayout

Allows you to place visual elements near each other horizontally or vertically

Grid

Allows you to organize visual elements within rows and columns

AbsoluteLayout

A layout placed at a specified, fixed position

RelativeLayout

A layout whose position depends on relative constraints

ScrollView

Allows you to scroll the visual elements it contains

Frame

Draws a border and adds space around the visual element it contains

ContentView

A special layout that can contain hierarchies of visual elements and can be used to create custom controls in XAML

Remember that only one root layout is assigned to the Content property of a page, and that layout can then contain nested visual elements and layouts.

Alignment and spacing options

As a general rule, both layouts and controls can be aligned by assigning the HorizontalOptions and VerticalOptions properties with one of the property values from the LayoutOptions structure, summarized in Table 3. Providing an alignment option is very common. For instance, if you only have the root layout in a page, you will want to assign VerticalOptions with StartAndExpand so that the layout gets all the available space in the page (remember this consideration when you experiment with layouts and views in this chapter and the next one).

Table 3: Alignment options in Xamarin.Forms

Alignment

Description

Center

Aligns the visual element at the center

CenterAndExpand

Aligns the visual element at the center and expands its bounds to fill the available space

Start

Aligns the visual element at the left

StartAndExpand

Aligns the visual element at the left and expands its bounds to fill the available space

End

Aligns the visual element at the right

EndAndExpand

Aligns the visual element at the right and expands its bounds to fill the available space

You can also control the space between visual elements with three properties: Padding, Spacing, and Margin, summarized in Table 4.

Table 4: Spacing options in Xamarin.Forms

Spacing

Description

Margin

Represents the distance between the current visual element and its adjacent elements with either a fixed value for all four sides, or with comma-separated values for the left, top, right, and bottom. It is of type Thickness, and XAML has built in a type converter for it.

Padding

Represents the distance between a visual element and its child elements. It can be set with either a fixed value for all four sides, or with comma-separated values for the left, top, right, and bottom. It is of type Thickness, and XAML has built in a type converter for it.

Spacing

Available only in the StackLayout container, it allows you to set the amount of space between each child element, with a default of 6.0.

I recommend you spend some time experimenting with how alignment and spacing options work in order to understand how to get the appropriate result in your user interfaces.

The StackLayout

The StackLayout container allows the placing of controls near each other, as in a stack that can be arranged both horizontally and vertically. As with other containers, the StackLayout can contain nested panels. The following code shows how you can arrange controls horizontally and vertically. Code Listing 5 shows an example with a root StackLayout and two nested layouts.

Code Listing 5

<?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:local="clr-namespace:App1"

             x:Class="App1.MainPage">

 

    <StackLayout Orientation="Vertical">

        <StackLayout Orientation="Horizontal" Margin="5">

            <Label Text="Sample controls" Margin="5"/>

            <Button Text="Test button" Margin="5"/>

        </StackLayout>

        <StackLayout Orientation="Vertical" Margin="5">

            <Label Text="Sample controls" Margin="5"/>

            <Button Text="Test button" Margin="5"/>

        </StackLayout>

    </StackLayout>

</ContentPage>

The result of the XAML in Code Listing 5 is shown in Figure 18.

Arranging visual elements with the StackLayout

Figure 18: Arranging visual elements with the StackLayout

The Orientation property can be set as Horizontal or Vertical, and this determines the final layout. If not specified, Vertical is the default. One of the main benefits of XAML code is that element names and properties are self-explanatory, and this is the case in StackLayout’s properties, too. Remember that controls within a StackLayout are automatically resized according to the orientation. If you do not like this behavior, you need to specify WidthRequest and HeightRequest properties on each control, which represent the width and height, respectively. Spacing is a property that you can use to adjust the amount of space between child elements; this is preferred to adjusting the space on the individual controls with the Margin property.

The Grid

The Grid is one of the easiest layouts to understand, and probably the most versatile. It allows you to create tables with rows and columns. In this way, you can define cells, and each cell can contain a control or another layout storing nested controls. The Grid is versatile in that you can just divide it into rows or columns, or both. The following code defines a Grid that is divided into two rows and two columns:

<Grid>

   <Grid.RowDefinitions>

      <RowDefinition />

      <RowDefinition />

   </Grid.RowDefinitions>

   <Grid.ColumnDefinitions>

      <ColumnDefinition />

      <ColumnDefinition />

   </Grid.ColumnDefinitions>

</Grid>

RowDefinitions is a collection of RowDefinition objects, and the same is true for ColumnDefinitions and ColumnDefinition. Each item represents a row or a column within the Grid, respectively. You can also specify a Width or a Height property to delimit row and column dimensions; if you do not specify anything, both rows and columns are dimensioned at the maximum size available. When resizing the parent container, rows and columns are automatically rearranged.

The preceding code creates a table with four cells. To place controls in the Grid, you specify the row and column position via the Grid.Row and Grid.Column properties, known as attached properties, on the control. Attached properties allow for assigning properties of the parent container from the current visual element. The index of both is zero-based, meaning that 0 represents the first column from the left and the first row from the top. You can place nested layouts within a cell or a single row or column. The code in Code Listing 6 shows how to nest a grid into a root grid with children controls.

Tip: Grid.Row="0" and Grid.Column="0" can be omitted.

Code Listing 6

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"

            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

            x:Class="Layouts.GridSample">

    <ContentPage.Content>

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition />

                <RowDefinition />

            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>

                <ColumnDefinition />

                <ColumnDefinition />

            </Grid.ColumnDefinitions>

            <Button Text="First Button" />

            <Button Grid.Column="1" Text="Second Button"/>

            <Grid Grid.Row="1">

                <Grid.RowDefinitions>

                    <RowDefinition />

                    <RowDefinition />

                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>

                    <ColumnDefinition />

                    <ColumnDefinition />

                </Grid.ColumnDefinitions>

                <Button Text="Button 3" />

                <Button Text="Button 4" Grid.Column="1" />

            </Grid>

        </Grid>

    </ContentPage.Content>

</ContentPage>

Figure 19 shows the result of this code.

Arranging visual elements with the Grid

Figure 19: Arranging visual elements with the Grid

The Grid layout is very versatile, and is also a good choice (when possible) in terms of performance.

Spacing and proportions for rows and columns

You have fine-grained control over the size, space, and proportions of rows and columns. The Height and Width properties of the RowDefinition and ColumnDefinition objects can be set with values from the GridUnitType enumeration as follows:

  • Auto: Automatically sizes to fit content in the row or column
  • Star: Sizes columns and rows as a proportion of the remaining space
  • Absolute: Sizes columns and rows with specific, fixed height and width values

XAML has type converters for the GridUnitType values, so you simply pass no value for Auto, a * for Star, and the fixed numeric value for Absolute, such as:

<Grid.ColumnDefinitions>

   <ColumnDefinition />

   <ColumnDefinition Width="*"/>

   <ColumnDefinition Width="20"/>

</Grid.ColumnDefinitions>

Introducing spans

In some situations, you might have elements that should occupy more than one row or column. In these cases, you can assign the Grid.RowSpan and Grid.ColumnSpan attached properties with the number of rows and columns a visual element should occupy.

The AbsoluteLayout

The AbsoluteLayout container allows you to specify where exactly on the screen you want the child elements to appear, as well as their size and bounds. There are a few different ways to set the bounds of the child elements based on the AbsoluteLayoutFlags enumeration used during this process. The AbsoluteLayoutFlags enumeration contains the following values:

  • All: All dimensions are proportional
  • HeightProportional: Height is proportional to the layout
  • None: No interpretation is done
  • PositionProportional: Combines XProportional and YProportional
  • SizeProportional: Combines WidthProportional and HeightProportional
  • WidthProportional: Width is proportional to the layout
  • XProportional: X property is proportional to the layout
  • YProportional: Y property is proportional to the layout

Once you have created your child elements, you will need to assign the AbsoluteLayout.LayoutFlags attached property to set them at an absolute position within the container. You will also want to assign the AbsoluteLayout.LayoutBounds attached property to give the elements their bounds. Since Xamarin.Forms is an abstraction layer between Xamarin and the device-specific implementations, the positional values can be independent of the device pixels. This is where the layout flags mentioned previously come into play. Code Listing 7 provides an example based on proportional dimensions and absolute position for child controls.

Code Listing 7

<?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:local="clr-namespace:App1"

             x:Class="App1.MainPage">

 

    <AbsoluteLayout>

        <Label Text="First Label" 

               AbsoluteLayout.LayoutBounds="0, 0, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="Red"/>

        <Label Text="Second Label" 

               AbsoluteLayout.LayoutBounds="0.20, 0.20, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="Black"/>

        <Label Text="Third Label" 

               AbsoluteLayout.LayoutBounds="0.40, 0.40, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="Blue"/>

        <Label Text="Fourth Label" 

               AbsoluteLayout.LayoutBounds="0.60, 0.60, 0.25, 0.25"

               AbsoluteLayout.LayoutFlags="All" TextColor="Green"/>

    </AbsoluteLayout>

</ContentPage>

Figure 20 shows the result of the AbsoluteLayout example.

Absolute positioning with AbsoluteLayout

Figure 20: Absolute positioning with AbsoluteLayout

The RelativeLayout

The RelativeLayout container provides a way to specify the location of child elements relative either to each other or to the parent control. Relative locations are resolved through a series of Constraint objects that define each particular child element’s relative position to another. In XAML, Constraint objects are expressed through the ConstraintExpression markup extension, which is used to specify the location or size of a child view as a constant, or relative to a parent or other named view. Markup extensions are very common in XAML, and you will see many of them in Chapter 7 about data binding, but discussing them in detail is beyond the scope here. The official documentation has a very detailed page on their syntax and implementation that I encourage you to read.

In the RelativeLayout class, there are properties named XConstraint and YConstraint. In the next example, you will see how to assign a value to these properties from within another XAML element, through attached properties. This is demonstrated in Code Listing 8, where you meet the BoxView, a visual element that allows you to draw a colored box. In this case, it’s useful for giving you an immediate perception of how the layout is organized.

Code Listing 8

<?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:local="clr-namespace:App1"

             x:Class="App1.MainPage">

 

    <RelativeLayout>

        <BoxView Color="Red" x:Name="redBox"

        RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,

            Property=Height,Factor=.15,Constant=0}"

        RelativeLayout.WidthConstraint="{ConstraintExpression

            Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"

        RelativeLayout.HeightConstraint="{ConstraintExpression

            Type=RelativeToParent,Property=Height,Factor=.8,Constant=0}" />

        <BoxView Color="Blue"

        RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView,

            ElementName=redBox,Property=Y,Factor=1,Constant=20}"

        RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,

            ElementName=redBox,Property=X,Factor=1,Constant=20}"

        RelativeLayout.WidthConstraint="{ConstraintExpression

            Type=RelativeToParent,Property=Width,Factor=.5,Constant=0}"

        RelativeLayout.HeightConstraint="{ConstraintExpression

            Type=RelativeToParent,Property=Height,Factor=.5,Constant=0}" />

    </RelativeLayout>

</ContentPage>

The result of Code Listing 8 is shown in Figure 21.

Arranging visual elements with the RelativeLayout

Figure 21: Arranging visual elements with the RelativeLayout

Tip: The RelativeLayout container has poor rendering performance, and the documentation recommends that you avoid this layout whenever possible, or at least avoid more than one RelativeLayout per page.

The ScrollView

The special layout ScrollView allows you to present content that cannot fit on one screen, and therefore should be scrolled. Its usage is very simple:

    <ScrollView x:Name="Scroll1">

        <StackLayout>

            <Label Text="My favorite color:" x:Name="Label1"/>

            <BoxView BackgroundColor="Green" HeightRequest="600" />

        </StackLayout>

    </ScrollView>

You basically add a layout or visual elements inside the ScrollView and, at runtime, the content will be scrollable if its area is bigger than the screen size. Additionally, you can specify the Orientation property (with values Horizontal or Vertical) to set the ScrollView to scroll only horizontally or only vertically. The reason the layout has a name in the sample usage is that you can interact with the ScrollView programmatically, invoking its ScrollToAsync method to move its position based on two different options. Consider the following lines:

Scroll1.ScrollToAsync(0, 100, true);

Scroll1.ScrollToAsync(Label1, ScrollToPosition.Start, true);

In the first case, the content at 100px from the top is visible. In the second case, the ScrollView moves the specified control at the top of the view and sets the current position at the control’s position. Possible values for the ScrollToPosition enumeration are:

  • Center: Scrolls the element to the center of the visible portion of the view
  • End: Scrolls the element to the end of the visible portion of the view
  • MakeVisible: Makes the element visible within the view
  • Start: Scrolls the element to the start of the visible portion of the view.

Note that you should never nest ScrollView layouts, and you should never include the ListView and WebView controls inside a ScrollView because they both already implement scrolling.

The Frame

The Frame is a very special layout in Xamarin.Forms because it provides an option to draw a colored border around the visual element it contains, and an option to add extra space between the Frame’s bounds and the visual element. Code Listing 9 provides an example.

Code Listing 9

<?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:local="clr-namespace:App1"

             x:Class="App1.MainPage">

 

    <Frame OutlineColor="Red" CornerRadius="3" HasShadow="True" Margin="20">

        <Label Text="Label in a frame"

               HorizontalOptions="Center"

               VerticalOptions="Center"/>

    </Frame>

</ContentPage>

The OutlineColor property is assigned with the color for the border, the CornerRadius property is assigned with a value that allows you to draw circular corners, and the HasShadow property allows you to display a shadow. Figure 22 provides an example.

Drawing a Frame

Figure 22: Drawing a Frame

The Frame will be resized proportionally based on the parent container’s size.

The ContentView

The special container ContentView allows for aggregating multiple views into a single view and is useful for creating reusable, custom controls. Because the ContentView represents a stand-alone visual element, Visual Studio makes it easier to create an instance of this container with a specific item template. In the Solution pad, you can right-click the PCL name, and then select Add > New File. In the New File dialog, select the Forms node, then the Forms Content View Xaml item, as shown in Figure 23.

Adding a ContentView

Figure 23: Adding a ContentView

When the new file is added to the project, the XAML editor shows basic content made of the ContentView root element and a Label. You can add multiple visual elements, as shown in Code Listing 10, and then you can use the ContentView as you would with an individual control or layout.

Code Listing 10

<?xml version="1.0" encoding="UTF-8"?>

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 

             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             x:Class="App1.View1">

  <ContentView.Content>

      <StackLayout>

          <Label Text="Enter your email address:" />

          <Entry x:Name="EmailEntry" />

      </StackLayout>

  </ContentView.Content>

</ContentView>

It is worth mentioning that visual elements inside a ContentView can raise and manage events and support data binding, which makes the ContentView very versatile, and perfect for building reusable views.

Chapter summary

Mobile apps require dynamic user interfaces that can automatically adapt to the screen size of different device form factors. In Xamarin.Forms, creating dynamic user interfaces is possible through a number of so-called layouts. The StackLayout allows you to arrange controls near one another both horizontally and vertically; the Grid allows you to arrange controls within rows and columns; the AbsoluteLayout allows you to give controls an absolute position; the RelativeLayout allows you to arrange controls based on the size and position of other controls or containers; the ScrollView layout allows you to scroll the content of visual elements that do not fit in a single page; the Frame layout allows you to draw a border around a visual element; and the ContentView allows you to create reusable views.

Now that you have a basic knowledge of layouts, it’s time to discuss common controls in Xamarin.Forms that allow you to build the functionalities of the user interface, arranged within the layouts you learned in this chapter.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.