More Adaptive Techniques with Content Views and Master Detail
In my previous blog post I covered the basic tips for building adaptive Xamarin.Forms apps for tablets and phones. In this post I'm going to complete the discussion with two very adaptive-friendly components that make app development fun - ContentView and MasterDetailPage. Finally, I've also assembled a sample application you can download that combines many of the tips along with these components.
Content Views
Content Views are kind of like User Controls if you’re familiar with any previous Windows development platform, which allow you to create reusable parts of your UI. Imagine an app with three areas of content. On a tablet you may prefer to show it all on one page. On a phone, you may prefer to show each area of content in a separate tab. The way you implement this is by first creating each part of your UI as a ContentView. At the time of this writing, Xamarin hasn’t provided all the templates yet for every type of element, but you can just create a new XAML page and rename the ContentPage to ContentView in XAML and the code-behind as such: Within each ContentView you can perform minimal device-specific techniques using OnIdiom, as I discussed in my previous post, to handle tablet vs phone differences. Then, you want to create a Page for tablet users, and a TabbedPage for phone users. Each page can access and share the same ContentViews by referencing them in XAML using the xmlns (XML namespace) helper like such: Of course, the tablet page can contain a Grid layout and the phone page will have a single ContentView placed in each tab. You create a tabbed Page just like you create a ContentView. There is no template so you just have to create a regular ContentPage and then rename the tags here. The way a Tabbed page works is that it expects each child within the tag to be a navigation page. So here I’ve declared three Navigation pages and using this syntax you see here, I’m able to pass in my content view as an argument for each page. You’ll also notice I’ve wrapped each Contentview in a content page. I think it’s because I’m essentially creating a new navigation page from existing content, and that can only be another page. It looks a little redundant but it works and eliminates the need to create so many files, as you might first try to create a separate page to host each Content View. Next we just need to add one little directional piece of code that directs tablet apps to the SinglePage and phone apps to the Tabbed page. Here I’ve just used the DeviceIdiom check right in my app.cs file, and I set the MainPage accordingly.
// The root page of your application
if (Xamarin.Forms.Device.Idiom == TargetIdiom.Phone)
{
MainPage = new Views.Page3Tabbed();
}
else
{
MainPage = new Views.Paged3Single();
}
The important takeaway here is that we’re reusing these ContentViews without having to duplicate any of the critical UI or code-behind that may live on each of these views. That is part of the goal of developing an adaptive UI. We are creating multiple Pages for each version however these pages are just empty frames and require little maintenance compared to if we duplicated all UI content on each page. By modularizing the UI we can also easily change it. Of course, my sample is just empty, colored blocks but I hope you see the real value this technique has :)
MasterDetailPage
While most of the standard pages and views in Xamarin.Forms look and behave the exact same on phone and tablet, there is one type of page that offers a unique adaptive view per device. The MasterDetailPage. The MasterDetailPage is a single page template that manages two pages or two areas of content – a master pane that typically will display a list of navigation items, and a detail page of content. When you create a master detail page it’s recommended that the master page is a ContentPage and the detail pages can be Content, Tabbed or Navigation pages. But what you may not realize is that you can put ANY content in these pages. You aren’t restricted to making a ListView in the master page, for instance. The way it works is you create a XAML page and rename the ContentPage to MasterDetailPage. Then the key two properties to set are the Master and Detail. Each expects a Page. In my sample here I defined my "Master" content page right here in the markup for the master detail page. It's a ListView that will display all pages (download the full sample to see how it's populated).
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MasterDetailContentViews.MyMasterDetailPage">
<MasterDetailPage.Master>
<ContentPage Icon="Hamburger.png" Title="Personal Organizer">
<StackLayout VerticalOptions="FillAndExpand">
<ListView x:Name="listView" VerticalOptions="FillAndExpand" SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
</MasterDetailPage>
And then in code-behind we can programmatically set the Detail page as we need to. In this case I’m listening to the Selected event of the ListView and launching a page based upon the selection.
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
listView.SelectedItem = null;
}
}
You have a few options to customize the behavior of the master page. By default, it will display as a split view on landscape tablets and on phones it will slide out.
Combining ContentViews with MasterDetailPage
To show that you can really make the content of each part of the master detail anything you want, I’ve created a sample that combines the two techniques. It uses the MasterDetailPage to create this menu panel, and in the Details of one of the pages it shows how you can use a TabbedPage phones (within a Master Detail), and a single page layout for tablets. Download MasterDetailContentViews.zip
Conclusion
From the basic tips like Device.Idiom to the MasterDetailPage components, I've covered pretty much everything there is to know about building adaptive Xamarin.Forms apps today. Xamarin (or Microsoft) is still busy advancing the platform so maybe we'll see more tools and classes to help.
RelativeLayout
There is one other component that I personally hate but it does technically have a purpose with adaptive apps and that is the RelativeLayout control. The RelativeLayout control places constraints on its children to determine its layout, so it will always appear relatively the same on any device size. Its fans claim that it's easier to understand and read than a Grid since it may require less XAML to type? Sure it may be less XAML but as far as easier to read I'll let you be the judge. It may be pretty slick for drawing a red box, but if your layout will consist of many rows and columns you may as well use a control designed to create rows and columns. That's just my opinion.
This article was revised to include a third blog to this series. Check out Tips for Building Adaptive Apps with Xamarin.Forms - Part 3