February 2015

Volume 30 Number 2


Cross-Platform - Share UI Code Across Mobile Platforms with Xamarin.Forms

By Jason Smith | February 2015

With Xamarin, you can use C# to build beautiful native mobile apps and share most of your code between platforms. Traditionally, you had to design a separate UI for each targeted platform. But with Xamarin.Forms, you can build one UI that renders natively across all of them.

Xamarin.Forms is a cross-platform UI abstraction layer. You can use it to share UI and back-end code between platforms and yet still deliver a fully native UI experience. Because they’re native, your controls and widgets have the look and feel of each target platform.

Xamarin.Forms is fully compatible with the Model-View-ViewModel (MVVM) design pattern so you can bind page elements to properties and commands in a view model class.

If you prefer to design your pages declaratively, you can use XAML, a markup language with features such as resource dictionaries, dynamic resources, data binding, commands, triggers and behaviors.

Xamarin.Forms has a small, easy-to-use API. If you need deeper access to the native UI of a platform, you can create custom views and platform-specific renderers. This sounds complicated, but it’s really just a way to get to native UIs, and there are plenty of samples on the Xamarin Web site to help you do it.

You can start by using any of the readymade pages, layouts and views that come with Xamarin.Forms. As your app matures and you discover new use cases and design opportunities, you might come to rely on Xamarin.Forms support for XAML, MVVM, custom platform-specific renderers, and a variety of other features such as animations and data templates.

I’ll provide an overview of the Xamarin functionality with specific examples to illustrate how to share the bulk of your UI code across different target platforms and incorporate platform-specific code when needed.

Getting Started

First, open the NuGet package manager in Visual Studio or Xamarin Studio and check for new releases of Xamarin.Forms. Because you won’t be notified about new releases just by opening a Xamarin.Forms solution in either IDE, checking for updated NuGet packages is the only way to ensure you get the latest enhancements.

Create a Xamarin.Forms Solution When you’re sure you’ve got the latest version of Xamarin.Forms, create a Blank App (Xamarin.Forms Portable) solution.

Your solution has three platform-specific projects and one Portable Class Library (PCL). Create your pages in the PCL. Start by creating a basic login page.

Use C# to Create a Page Add a class to your PCL project. Then add controls (called “views” in Xamarin), as shown in Figure 1.

Figure 1 Adding Views (Controls)

public class LogInPage : ContentPage
{
  public LogInPage()
  {
    Entry userEntry = new Entry { Placeholder = "Username" };
    Entry passEntry =
      new Entry { Placeholder = "Password", IsPassword = true };
    Button submit = new Button { };
    Content = new StackLayout
    {
      Padding = 20,
      VerticalOptions = LayoutOptions.Center,
      Children = { userEntry, passEntry, submit }
    };
  }
}

To show the page when an app starts, open the MyApp class and assign an instance of it to the MainPage property:

public class MyApp : Application
{
  public MyApp()
  {
    MainPage = new LogInPage();
  }
}

This is a good time to discuss the Application class. Starting in v1.3.0, all Xamarin.Forms apps will contain this class. It’s the entry point of a Xamarin.Forms app and, among other things, it provides lifecycle events, as well as a persistent data store (the Properties dictionary) for any serializable data. If you have to get to an instance of this class from anywhere in your app, you can use the static Application.Current property.

In the preceding example, I removed the default code inside of the application class and replaced it with a single line of code that makes the LogInPage appear when you run the app. It appears when the app runs because this code assigns a page (the LogInPage) to the MainPage property of the Application class. You have to set it in the constructor of the Application class.

You can also override three methods in this class:

  • The OnStart method, which is called when an app is first started.
  • The OnSleep method, which is called when the app is about to go into a background state.
  • The OnResume method, which is called when an app returns from a background state.

In general, pages aren’t very interesting until you connect them with some sort of data or behavior, so I’ll show how to do that.

Bind a Page to Data If you use the MVVM design pattern, you might create a class such as the one in Figure 2 that implements the INotifyPropertyChanged interface.

Figure 2 Implementing the INotifyPropertyChanged Interface

public class LoginViewModel : INotifyPropertyChanged
{
  private string usrnmTxt;
  private string passWrd;
  public string UsernameText
  {
    get { return usrnmTxt; }
    set
    {
      if (usrnmTxt == value)
        return;
      usrnmTxt = value;
      OnPropertyChanged("UsernameText");
    }
  }
  public string PassWordText
  {
    get { return passWrd; }
    set
    {
      if (passWrd == value)
        return;
      passWrd = value;
      OnPropertyChanged("PassWrd");
    }
  }
  public event PropertyChangedEventHandler PropertyChanged;
  private void OnPropertyChanged(string propertyName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

You can bind the views of your login page to the properties of that class, as shown in Figure 3.

Figure 3 Binding Views to Class Properties

public LogInPage()
{
  Entry userEntry = new Entry { Placeholder = "Username" };
  userEntry.SetBinding(Entry.TextProperty, "UsernameText");
  Entry passEntry =
    new Entry { Placeholder = "Password", IsPassword = true };
  passEntry.SetBinding(Entry.TextProperty, "PasswordText");
  Button submit = new Button { Text = "Submit" };
  Content = new StackLayout
    {
      Padding = 20,
      VerticalOptions = LayoutOptions.Center,
      Children = { userEntry, passEntry, submit }
    };
  BindingContext = new LoginViewModel();
}

To read more about how to bind to data in your Xamarin.Forms app, see “From Data Bindings to MVVM” on the Xamarin site at bit.ly/1uMoIUX.

Use XAML to Create a Page For smaller apps, creating your UIs by using C# is a perfectly reasonable approach. However, as the size of your app grows, you might find yourself typing a lot of repetitive code. You can avoid that problem by using XAML instead of C# code.

Add a Forms XAML Page item to your PCL project. Then add markup to the page, as shown in Figure 4.

Figure 4 Adding Markup to a Forms XAML Page

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="https://xamarin.com/schemas/2014/forms"
  xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
  x:Class="Jason3.LogInPage"
  xmlns:local="clr-namespace:XamarinForms;assembly=XamarinForms"> 
    <StackLayout VerticalOptions="Center">
      <StackLayout.BindingContext>
        <local:LoginViewModel />
      </StackLayout.BindingContext>
      <Entry Text="{Binding UsernameText}" Placeholder="Username" />
      <Entry Text="{Binding PasswordText}"
        Placeholder="Password" IsPassword="true" />
      <Button Text="Login" Command="{Binding LoginCommand}" />
    </StackLayout>
</ContentPage>

The XAML in Figure 4 might look familiar if you’ve written Windows Presentation Foundation (WPF) apps. However, the tags are different because they refer to Xamarin.Forms types. Also, the root element refers a subclass of the Xamarin.Forms.Element class. All XAML files in a Xamarin.Forms app must do this.

To read more about using XAML to create pages in a Xamarin.Forms app, see “XAML for Xamarin.Forms” on the Xamarin Web site at bit.ly/1xAKvRN.

Design for a Specific Platform

Xamarin.Forms has a relatively small number of APIs compared with other native mobile platforms. That makes it easier for you to design your pages, but sometimes Xamarin.Forms doesn’t render a view exactly the way you want it to on one or more of your platform targets.

If you run up against this barrier, just create a custom view, which is just a subclass of any view that’s available in Xamarin.Forms.

To make the view appear on a page, extend the view renderer. In more advanced cases, you can even create a custom renderer from scratch. Custom renderer code is specific to a platform, so you can’t share it. But this approach could be worth the cost in order to introduce native features and usability to the app.

Create a Custom View First, create a subclass of any view that’s available in Xamarin.Forms. Here’s code for two custom views:

public class MyEntry : Entry {}
public class RoundedBoxView : BoxView {}

Extend an Existing RendererFigure 5 extends the renderer that renders the Entry view for the iOS platform. You’d put this class in the iOS platform project. This renderer sets the color and style of the underlying native text field.

Figure 5 Extending an Existing Renderer

[assembly: ExportRenderer (typeof (MyEntry), typeof (MyEntryRenderer))]
namespace CustomRenderer.iOS
{
  public class MyEntryRenderer : EntryRenderer
  {
    protected override void OnElementChanged
      (ElementChangedEventArgs<Entry> e)
    {
      base.OnElementChanged (e);
      if (e.OldElement == null) {
        var nativeTextField = (UITextField)Control;
        nativeTextField.BackgroundColor = UIColor.Gray;
        nativeTextField.BorderStyle = UITextBorderStyle.Line;
      }
    }
  }
}

You can do just about anything you want in your renderer because you’re referencing native APIs. If you want to view the sample that contains this snippet, see “Xamarin.Forms Custom Renderer” at bit.ly/1xTIjmR.

Create a Renderer from Scratch You can create a brand-new renderer that doesn’t extend any other renderers. You’ll do a bit more work, but it makes sense to create one if you want to do any of these things:

  • Replace the renderer of a view.
  • Add a new view type to your solution.
  • Add a native control or native page to your solution.

For example, if you want to add a native UIView control to a page in the iOS version of your app, you could add a custom renderer to your iOS project, as shown in Figure 6.

Figure 6 Adding a Native UIView Control to an iOS App with a Custom Renderer

[assembly: ExportRendererAttribute(typeof(RoundedBoxView),
  typeof(RoundedBoxViewRenderer))]
namespace RBVRenderer.iOS
{
  public class RoundedBoxViewRenderer :
    ViewRenderer<RoundedBoxView,UIView>
  {
    protected override void OnElementChanged(
      ElementChangedEventArgs<RoundedBoxView> e)
    {
      base.OnElementChanged(e);
      var rbvOld = e.OldElement;
      if (rbvOld != null)
      {
        // Unhook any events from e.OldElement here.
      }
      var rbv = e.NewElement;
      if (rbv != null)
      {
        var shadowView = new UIView();
        // Set properties on the UIView here.
        SetNativeControl(shadowView);
        // Hook up any events from e.NewElement here.
      }
    }
  }
}

The general pattern that appears in this renderer ensures you can use it in virtualized layouts such as a list view, which I’ll discuss later.

If you want to view the sample that contains this snippet, see bit.ly/xf-customrenderer.

Add Properties to a Custom View You can add properties to a custom view, but just make sure you make them bindable so you can bind them to properties in a view model or to other types of data. Here’s a bindable property in the RoundedBoxView custom view:

public class RoundedBoxView : BoxView
{
  public static readonly BindableProperty CornerRadiusProperty =
    BindableProperty.Create<RoundedBoxView, double>(p => p.CornerRadius, 0);
  public double CornerRadius
  {
    get { return (double)base.GetValue(CornerRadiusProperty);}
    set { base.SetValue(CornerRadiusProperty, value);}
  }
}

To connect new properties to your renderer, override the OnElementPropertyChanged method of the renderer and add code that runs when the property changes:

protected override void OnElementPropertyChanged(object sender,    
  System.ComponentModel.PropertyChangedEventArgs e)
{
  base.OnElementPropertyChanged(sender, e);
  if (e.PropertyName ==
    RoundedBoxView.CornerRadiusProperty.PropertyName)
      childView.Layer.CornerRadius = (float)this.Element.CornerRadius;
}

To learn more about creating custom views and custom renderers, see “Customizing Controls for Each Platform” at bit.ly/11pSFhL.

Pages, Layouts and Views: The Building Blocks of Xamarin.Forms

I’ve showcased a few elements, but there are many more. This would be a good time to visit them.

Xamarin.Forms apps contain pages, layouts and views. A page contains one or more layouts, and a layout contains one or more views. The term view is used in Xamarin to describe what you might be used to calling a control. In total, the Xamarin.Forms framework contains five page types, seven layout types and 24 view types. You can read more about them at xamarin.com/forms. I’ll visit some important page types later, but first I’ll take a moment to review some of the layouts you can use in your app. Xamarin.Forms contains four primary layouts:

  • StackLayout: The StackLayout positions child elements in a single line that can be oriented vertically or horizontally. You can nest StackLayouts to create complex visual hierarchies. You can control how views are arranged in a StackLayout by using the VerticalOptions and Horizontal­Options properties of each child view.
  • Grid: The Grid arranges views into rows and columns. This layout is similar to the one you get with WPF and Silverlight except you can add spacing between rows and columns. You do that by using the RowSpacing and ColumnSpacing properties of the Grid.
  • RelativeLayout: The RelativeLayout positions views by using constraints relative to other views.
  • AbsoluteLayout: The AbsoluteLayout lets you position child views in two ways: at an absolute position, or proportionally relative to the parent. This can be useful if you plan to create split and overlaid hierarchies. Figure 7 shows an example.

Figure 7 Using the AbsoluteLayout

void AbsoluteLayoutView()
{
  var layout = new AbsoluteLayout();
  var leftHalfOfLayoutChild = new BoxView { Color = Color.Red };
  var centerAutomaticallySizedChild =
    new BoxView { Color = Color.Green };
  var absolutelyPositionedChild = new BoxView { Color = Color.Blue };
  layout.Children.Add(leftHalfOfLayoutChild,
    new Rectangle(0, 0, 0.5, 1),
    AbsoluteLayoutFlags.All);
  layout.Children.Add(centerAutomaticallySizedChild,
    new Rectangle(
    0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize),
    AbsoluteLayoutFlags.PositionProportional);
  layout.Children.Add(
    absolutelyPositionedChild, new Rectangle(10, 20, 30, 40));
}

Note that all layouts give you a property named Children. You can use that property to access additional members. For example, you can use the Children property of the Grid layout to add and remove rows and columns, as well as specify row and column spans.

Show Data in a Scrolling List

You can show data in a scrolling list by using a list view form (named ListView). This view performs well because the renderers for each cell in the list are virtualized. Because each cell is virtualized, it’s important that you properly handle the OnElementChanged event of any custom renderers that you create for cells or lists by using a pattern similar to the one shown earlier.

First, define a cell, as shown in Figure 8. All data templates for a ListView must use a Cell as the root element.

Figure 8 Defining a Cell for a ListView

public class MyCell : ViewCell
{
  public MyCell()
  {
    var nameLabel = new Label();
    nameLabel.SetBinding(Label.TextProperty, "Name");
    var descLabel = new Label();
    descLabel.SetBinding(Label.TextProperty, "Description");
    View = new StackLayout
    {
      VerticalOptions = LayoutOptions.Center,
      Children = { nameLabel, descLabel }
    };
  }
}

Next, define a data source and set the ItemTemplate property of the ListView to a new data template. The data template is based on the MyCell class created earlier:

var items = new[] {
  new { Name = "Flower", Description = "A lovely pot of flowers." },
  new { Name = "Tuna", Description = "A can of tuna!" },
  // ... Add more items
};
var listView = new ListView
{
  ItemsSource = items,
  ItemTemplate = new DataTemplate(typeof(MyCell))
};

You can do this in XAML by using the following markup:

<ListView ItemsSource="{Binding Items}">
  <ListView.ItemTemplate>
    <ViewCell>
      <StackLayout VerticalOptions="center">
      <Label Text="{Binding Name}" />
      <Label Text="{Binding Description}" />
      </StackLayout>
    </ViewCell>
  </ListView.ItemTemplate>
</ListView>

Most apps contain more than one page, so you’ll need to enable users to navigate from one page to another. The following pages have built-in support for page navigation and support full-screen modal page presentation:

  • TabbedPage
  • MasterDetailPage
  • NavigationPage
  • CarouselPage

You can add your pages as children to any of these four pages and get navigation for free.

The Tabbed Page A TabbedPage shows an array of tabs across the top of a screen. Assuming your PCL project contains pages named LogInPage, DirectoryPage and AboutPage, you could add them all to a TabbedPage by using the following code:

var tabbedPage = new TabbedPage
{
  Children =
  {
    new LoginPage { Title = "Login", Icon = "login.png" },
    new DirectoryPage { Title = "Directory", Icon = "directory.png" },
    new AboutPage { Title = "About", Icon = "about.png" }
  }
};

In this case, it’s important to set the Title and Icon property of each page so that something appears on page tabs. Not all platforms render icons. That depends on the platform’s tab design.

If you opened this page on a mobile device, the first tab would appear as selected. However, you can change that by setting the CurrentPage property of the TabbedPage page.

The NavigationPage A NavigationPage manages the navigation and UX of a stack of pages. This page offers you the most common type of mobile app navigation pattern. Here’s how you would add your pages to it:

var loginPage = new LoginPage();
var navigationPage = new NavigationPage(loginPage);
loginPage.LoginSuccessful += async (o, e) => await
  navigationPage.PushAsync(new DirectoryPage());

Notice the use of PushAsync as a way to navigate users to a specific page (in this case the DirectoryPage). In a NavigationPage, you “push” pages onto a stack and then “pop” them off as users navigate backward to the previous page.

The PushAsync and PopAsync methods of a NavigationPage are asynchronous so your code should await them and not push or pop any new pages while the task is running. The task of each method returns after the animation of a push or pop completes.

For convenience, all Xamarin.Forms views, layouts and pages contain a Navigation property. This property is a proxy interface that contains the PushAsync and PopAsync methods of a NavigationPage instance. You could use that property to navigate to a page instead of calling the PushAsync and PopAsync methods on the NavigationPage instance directly. You can also use the NavigationProperty to get to the PushModalAsync and PopModalAsync methods. This is useful if you want to replace the contents of the entire screen with a new modal page. You don’t have to have a NavigationPage in the parent stack of a view to use the Navigation property of a view, but nonmodal PushAsync/PopAsync operations might fail.

A Note about Design Patterns As a general practice, consider adding NavigationPages as children to TabbedPages, and TabbedPages as children to MasterDetailPages. Certain types of patterns can cause an undesirable UX. For example, most platforms advise against adding a TabbedPage as a child of a NavigationPage.

Animate Views in a Page

You create a more engaging experience by animating the views on a page, which can be done in two ways. Either choose built-in animations that come with Xamarin.Forms or build one yourself by using the animation API.

For example, you could create a fading effect by calling the FadeTo animation of a view. The FadeTo animation is built into a view so it’s easy to use:

async Task SpinAndFadeView(View view)
{
  await view.FadeTo(20, length: 200, easing: Easing.CubicInOut);
}

You can chain a series of animation together by using the await keyword. Each animation executes after the previous one completes. For example, you could rotate a view just before you fade it into focus:

async Task SpinAndFadeView(View view)
{
  await view.RotateTo(180);
  await view.FadeTo(20, length: 200, easing: Easing.CubicInOut);
}

If you have trouble achieving the effect you want, you can use the full animation API. In the following code, the view fades halfway through the rotation:

void SpinAndFadeView(View view)
{
  var animation = new Animation();
  animation.Add(0, 1, new Animation(
    d => view.Rotation = d, 0, 180, Easing.CubicInOut));
  animation.Add(0.5, 1, new Animation(
    d => view.Opacity = d, 1, 0, Easing.Linear));
  animation.Commit(view, "FadeAndRotate", length: 250);
}

This example composes each animation into a single Animation instance and then runs the entire animation sequence by using the Commit method. Because this animation isn’t tied to a specific view, you can apply the animation to any of them.

Wrapping Up

Xamarin.Forms is an exciting new way to build cross-platform native mobile apps. Use it to build a UI that renders natively across iOS, Android and Windows Phone. You can share almost all of your code between platforms.

Xamarin Inc. built Xamarin and Xamarin.Forms to make it possible for C# developers to jump into mobile development virtually overnight. If you’ve developed for the Windows Runtime, WPF or Silverlight, then you’ll find that Xamarin.Forms is an easy bridge into the world of cross-platform native mobile development. You can install Xamarin today and immediately start to use C# to build beautiful native apps that run on iOS, Android and Windows Phone devices.


Jason Smith is an engineering technical lead at Xamarin Inc. in San Francisco, currently leading the Xamarin.Forms project. He was one of the principal architects of Xamarin.Forms, prior to which he contributed to the Xamarin Studio project and was part of the initial research that lead to the creation of Xamarin Test Cloud.

Thanks to the following Microsoft technical expert for reviewing this article: Norm Estabrook
Norm Estabrook has been a content developer at Microsoft for more than 10 years with a special focus on helping developers build Office extensions and native mobile apps by using Visual Studio. He’s published numerous articles for the MSDN library and resides in northwest Washington with his wife, two kids and a very sweet visually impaired Miniature Schnauzer