1. Home
  2. Training Library
  3. Programming
  4. Programming Courses
  5. Building a Xamarin Forms UI - Layout Containers

XAML Containers


Layout Containers
XAML Containers
PREVIEW23m 14s
3m 15s

The course is part of this learning path

XAML Containers

Building a Xamarin Forms UI - Layout Containers is a practical deep dive into the basics of using Xamarin Forms to design and lay out a mobile app's user interface. Xamarin Forms offers several built-in layout frameworks for positioning UI elements on a screen. We look at four of the most common ones to see how they work and the pros and cons of using each. We start with StackLayout, then move on to AbsoluteLayout, Grid layout, and finish with RelativeLayout.


Source code



Let's start by creating a new blank template for an Android and iOS app imaginatively called Xaml_UI. It will be a Model View View-Model app, so I'll create the appropriate folder structure. Models will contain the classes and files related to the app's data. That's either data stored locally or the mechanisms to communicate with remote data like a web service. The views folder will contain the XAML user interface files and classes. The viewmodels folder will house the classes that glue the views to models, that is, the user interfaces to the data, and contain most of the app's business logic. These folders double as namespaces, so when I create a file within a folder, it belongs to the app.folder namespace. You'll see what I mean in a minute or two.

At the top of the XAML container hierarchy, we have the ContentPage, analogous to a window in desktop programming or an HTML page in a web application. You can see in the boilerplate MainPage that the content page is the outermost element. Next in the hierarchy is the content view, also defined in its own file. A content view is a group of UI elements embedded as one control within a content page or another content view. 

Keeping with the object-oriented paradigm, views come in several derivatives. The Frame class is a content view with a border, drop shadow, and rounded corners, while a scroll view is, you've guessed it, a scrollable view. Several other content view descendants implement variations on the default behavior. 

XAML is like HTML in many respects, and like HTML, content is nested in a page within layout containers. There are five layouts for arranging controls and content. Let's look at each of them by creating content views - first, the stack layout. 

Right-click on the Views folder, select add, and then new item. I'll select content view without C#, so that's a xaml view, and I'll name it StackLayoutView. As you can see, stack layout is the default layout when creating a new view or page. Stack layout is akin to responsive frameworks like bootstrap, where elements are stacked upon one another and dynamically adjust to the view's size. With the variety of mobile device screen sizes, the stack layout makes a lot of sense. We can see the class attribute with the Views namespace in the content view header tag. Looking at the code-behind file, we can also see the new Views namespace.

Before we get underway implementing the stack layout, I need to embed the stack layout view within the MainPage to see the adjustments we make in the device emulator via hot reload. In the MainPage xaml, go into the ContentPage element at the top and add an xmlns local attribute pointing to the Views namespace. This is equivalent to a using or include statement that you would find in other programming languages. That will remain grayed out until I add the content view to the page. I'm just going to change the name of my view from stacked layout to stack layout. I was going to say if, but realistically when, you need to do this, you have to rename the class in the code-behind file and the class reference in the Xaml header.

First, I'll delete the boilerplate code and then add the view using the local keyword followed by a colon and the content view name. You can only have one root element within the ContentPage. Okay, let's run that. Right, there we have our MainPage displaying the very minimalist StackLayoutView. Now let's add some colored boxes to see how the stack layout operates. First, I'll add a frame with rounded corners, a margin of 10, and an indigo background color. I'll give the view a suitable title label, centering the label and changing the font color to white. Next, I'll create another frame below but only set the border color this time. 

As you can see, I haven't specified a height parameter for either of the frames, but the top frame is taller as it contains a label. As I add content to the lower frame, it will expand. I can add another stack layout, but this time set the orientation to horizontal so that elements will go across the view. Instead of left or right, the horizontal options are start, center, and end. Again each frame takes up as much room as needed to display its content. If I add another horizontal stack layout, I can use horizontal option fill and expand to get the nested elements to fill the space. The stacked layout behaves as you'd hope when the device is rotated, maintaining the correct proportions.

Let's make the label text horizontal alignment match their parent's frame horizontal alignment. Again, the alignment uses start, center, and end.

I want to put these views on a single tabbed page, which I'll create under the views folder. I'll add a new tabbed page item. We need to add the StackLayoutView to the first tab and give the tab the appropriate title. Even though the tabbed layout page is defined within the Views namespace, the same as the StackLayoutView, we still need to add the views namespace reference to the tabbed page header. It's not because I called page instead of view.

In App.xaml.cs, I'll new up a tabbed layout page and assign it to MainPage. The app will go straight to the new tabbed page when I start debugging. I'll rename the first tab as stacked and get it to display my stacked layout view.

Next, I'll create an absolute layout view and paste in the elements from the stack layout. Understandably, we have some syntax errors as some of the layout instructions don't apply to an absolute layout. As the absolute name implies, an element's position and size are determined by four coordinates, left, top, width, and height. I'll add the AbsoluteLayoutView to the tabbed page and start debugging the app to use the hot reload feature to design the view.

Without making this my life's work, I'll try to get the absolute layout to match the earlier stacked layout as best as possible. 

As you can see, all elements are positioned relative to the top left of the view. First, I'll change the title, then set the layout to fill and expand vertically and horizontally. I'll set each element's top, left , width, and height using absolute layout bounds. There is another property called layout flags that can set either X, Y, width, height, or all properties to be proportional to the parent. If I set all the frame's properties proportionally, it might be something like 0, 0, 1, and 0.1. So 0's to position it at the top left, then 1 to say 100% of the width, and 0.1 for a tenth of the height. I'm going to push on with absolute values as we'll see another layout type that offers a proportional specification.

Not a bad facsimile, but let's see what happens when I rotate the screen. As you may have guessed, an asymmetrical absolute layout works as expected, but perhaps not as you'd hope, as all elements maintain their relationship and size with the top left corner of the screen. Even with a proportional layout, absolute static xaml won't give us an ideal solution.

The next layout cab off the rank is the grid layout, which I'll create inside a new content view – GridLayoutView. Before we get started with the grid, let's add the view to the tabbed page. It should come as no surprise that a grid layout is comprised of rows and columns, which we define first. It's pretty straightforward, and Visual Studio's IntelliSense helps. First, the row definitions, with a row definition element for each row we want in the grid. Row height can be an asterisk, which means the rows are all the same height; that is, the row height equals the grid height divided by the number of rows. Row heights can be absolute values expressed as the number of pixels, or the row can be some proportion of the asterisk height. 1.5* is one and half the height of the evenly divided rows, and .25 is a quarter. The grid columns are defined similarly but naturally use width instead of height. Once the grid space has been defined, we assign elements to the grid using grid.row or grid.column, with the row and column numbering starting at 0. Elements can span rows and columns with grid.rowspan and grid.columnspan respectively. I don't need seven rows to recreate the layout, but I feel that four equally sized rows in portrait orientation will be too big. I'll use a margin of ten to get the spacing around my frames. Let's run that and see what it looks like, knowing there will be some tweaking to do. I'll copy the colored frames from the stack layout to save time.

For the third and fourth rows of colored frames, I'll use the margin attribute specifying values for left, top, right, and bottom margins. The first row of colored frames with justified alignment, start, center, end, and expand horizontal options will do the trick. All the frames on the fourth row use fill and expand to set the correct alignment. Okay, we're heading in the right direction – I just need to fine-tune my row definition height values. That looks pretty good. How about in landscape orientation? Oh dear, that is no good at all.  What about removing the three empty bottom rows? It's an improvement of sorts in landscape orientation but fails in portrait. This is a scenario that would benefit from dynamic adjustment with C# code. In a future course, I'll look at manipulating the user interface in code.

Relative is the final layout I want to look at. There is the Flex layout, but as that is essentially a XAML implementation of Flex CSS, I'm not going to look at that. Once again, I'll create a new content view called relative layout view and add a new ContentPage referencing that view to my tabbed layout page. As with the other layout patterns, all elements are nested within a container, but as you might have guessed, this one uses the relative layout tag. Elements are positioned and sized using X, Y, height, and width constraints, prefixed with RelativeLayout. Each of these constraints is specified with an expression defined within curly braces. The type parameter of the expression tells us which element the expression is related to. In this case, RelativeToParent, means relative to the content view. The property parameter says which attribute of the relative control we're talking about. The factor or constant attribute specifies the value of the constraint. If we use factor, we are talking about a proportion of the property in question.

In the title bar case, we say that we want its width specified by RelativeLayout.Width constraint, to be the width of the parent multiplied by a factor of one. Long story short, we want the title bar to be the same width as the parent container, remembering that the 10 pixel margin is built into our relative layout. We need to set the Y constraint relative to the title bar for the frame containing the green box that needs to be under the title bar. We do that by changing the type from RelativeToParent to RelativeToView and then specify the view with the ElementName attribute. Here I'm saying set the Y constraint of the green-blue frame relative to the Y or top property of the title bar element plus a constant value of 70 pixels. As with the title bar element, I want to set the width to the parent content view. The relative layout means you'll have to name UI elements to reference then with relative to view, but in real apps, you'll need to name controls to reference them in the C# code.

We only need to set the top or Y constraint for the first red frame as the X value defaults to 0, putting it at the leftmost position. The width of the first red frame box is determined by its content, that is, the words "left box." The top of the first red frame is a little over twice that of the green-blue frame from the parent's top. I don't know if you've noticed the subtle difference between using a constant value when defining the Y constraint versus using a factor. When I specified the Y constraint for the green-blue frame, it was 70 pixels from the top of the title bar, that is, from the top of the element specified in the constraint expression. When I use the factor attribute, I'm specifying just over twice the distance from the parent's top as my relative view is from the parent's top. When using a constant, your anchor point is the element specified in the relative to attribute. When using the factor attribute, your anchor point is the parent, but you're using another element's relationship to the parent to determine the offset value. 

The bottom red frame is a 4.4 top red frame's height from the top of the content view. Having established the Y coordinate for the red frame, I can use it with a factor of 1 to establish the Y coordinates for all the other elements that share the same vertical relationship. Specifying the rest of the factors to get our layout looking right is a case of experimentation - this is where the hot reload functionality really comes into its own. In portrait mode, RelativeLayout looks, well, not perfect, but I've seen worse. There is no easy way to have RelativeLayout adjust dynamically in XAML. Ideally, we'd want in the case of the top yellow center box for the factor value to be a dynamic expression involving its width. As we shall see in a future course, this can be achieved with C# code.

About the Author
Learning Paths

Hallam is a software architect with over 20 years experience across a wide range of industries. He began his software career as a  Delphi/Interbase disciple but changed his allegiance to Microsoft with its deep and broad ecosystem. While Hallam has designed and crafted custom software utilizing web, mobile and desktop technologies, good quality reliable data is the key to a successful solution. The challenge of quickly turning data into useful information for digestion by humans and machines has led Hallam to specialize in database design and process automation. Showing customers how leverage new technology to change and improve their business processes is one of the key drivers keeping Hallam coming back to the keyboard. 

Covered Topics