The Future of Mobile Development: Xamarin.Forms 4.0 Preview

David Ortinau

Yesterday at Microsoft Connect(); 2018 we announced our plans for Xamarin.Forms 4.0 and shared a public preview. Let’s now take a deeper look at the big changes, starting with Xamarin.Forms Shell, and then touch some of the other highlights.

Through countless interviews, conversations, and surveys, we have heard your voice loud and clear. You want Xamarin.Forms to be easier to use “out of the box”, navigation to be ever present and easier to control, to have a more consistent design across iOS and Android, and to have a faster, more flexible list control. Get ready to preview Xamarin.Forms 4.0, which delivers on all those top feedback themes and so much more with Shell, Visual, and CollectionView.

Introducing Shell

We want to make it easier to get started with Xamarin.Forms by providing a guided structure for setting up your application. Shell gives you 3 tiers of elements to describe your application (see below), and then gets out of your way to start populating the app with content and features. You could think of Shell as the evolution of MasterDetailPage, NavigationPage, and TabbedPage.

With Shell you get:

  • A simplified way to express the high level of your application architecture in a single file (AppShell.xaml)
  • A hierarchy of common UI navigation patterns that suite your target mobile platforms : flyout menu, bottoms tabs, top tabs
  • A robust navigation service that provides URI-based routing so you can jump directly to any part of your application with ease
  • An extensible template-based infrastructure to easily customize elements of your UI
  • All that you have in Xamarin.Forms today and more to come on the Shell spec roadmap

To quickly get started, if you’re using Visual Studio 2019 on Windows, download and install our template pack that has updated templates based on Shell. Otherwise, no matter which IDE you prefer, you can easily walk through adding a Shell to your existing or new application. Once you have your application open, update to the Xamarin.Forms 4.0-pre NuGet (available via your favorite NuGet package manager).

Now you’ll need to enable Shell by adding a feature flag just before you initialize Xamarin.Forms in your MainActivity.cs  and AppDelegate.cs .

Android:

global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental");
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

iOS:

global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental");
global::Xamarin.Forms.Forms.Init();

Next, if you’re not using the templates mentioned above, add a new ContentPage with XAML to your project and rename it AppShell (or whatever you like, but we’re standardizing on AppShell for the moment). Now update the AppShell.xaml.cs to extend Xamarin.Forms.Shell instead. Reference the XAML below for a simple starting point.

<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:NewApp" 
    RouteScheme="app" 
    RouteHost="microsoft.com" 
    Route="newapp" 
    x:Class="NewApp.AppShell">

    <ShellItem Title="Home">
        <ShellSection>
            <ShellContent>
                <local:MainPage />
            </ShellContent>
        </ShellSection>
    </ShellItem>

</Shell>

In the content above, note the local:MainPage. This should be your starting ContentPage located in the local namespace.

using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace NewApp
{
    public partial class AppShell : Xamarin.Forms.Shell
    {
        public AppShell()
        {
            InitializeComponent();
        }
    }
}

The only other change you need to make to run your first Shell app is to swap your app’s MainPage to use Shell. Modify your App.xaml.cs as below:

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace NewApp
{
    public partial class App : Application
    {
        public App()
        {
           InitializeComponent();

            MainPage = new AppShell();
        }
    }
}

Save and run the app. You should see your main page, and a hamburger menu that opens a flyout with a single menu item. As mentioned above, there are 3 elements that made this happen: ShellItem, ShellSection, and ShellContent. Shell prescribes a hierarchy of content navigation from flyout to bottom tabs to top tabs as you go deeper in your app.

Element Description
ShellItem The top level grouping of content represented by an item in the flyout. Can contain multiple ShellSections.
ShellSection Groups the content of your application. This content is navigable by bottom tabs. Can contain one or more ShellContent. Multiple ShellContent are navigable by top tabs.
ShellContent The ContentPages of your application.

As lamented in the introduction, navigation can also be a troublesome beast to tame: TabbedPage, MasterDetailPage, NavigationPage, a series of plugins and custom implementations to handle flyouts, and intercepting navigation events to implement custom logic (cancel the back button!). In Shell you can navigate from anywhere to anywhere at any time with a new powerful routing API.

You have become accustomed to pushing and popping, but you’ve told us you’d like a better way to navigate through your application, and to add custom logic especially as the user tries to leave a screen. Shell’s new navigation aims to address exactly than, and provide some additional conveniences along the way. This all begins by defining your routing in your Shell.xaml as seen in the code above.

Description
RouteScheme URI scheme such as “http” or “app”. I prefer “app” since we’re making a mobile app.
RouteHost The domain portion of the URI.
Route The base segment of your application’s URI.

Putting this all together, you can construct a URI to the root of this application like “app://microsoft.com/newapp”. Here is an example of multiple pages in the application (displayed as top tabs):

 

<ShellItem Title="Home" Route="a">
    <ShellSection Route="b">
        <ShellContent Route="home">
            <local:MainPage />
        </ShellContent>
        <ShellContent Route="notifications">
            <local:NotificationsPage />
        </ShellContent>
    </ShellSection>
</ShellItem>

To programmatically navigate to the notifications page, the URI would be “app://microsoft.com/newapp/a/b/notifications”. If you have a page that isn’t part of the navigation structure that you wish to route to, then you only need register that route somewhere in your code before calling the route.

Routing.RegisterRoute("greeting", typeof(GreetingPage));

In the above example you have a new route “greeting” that will take the user to the GreetingPage. The last piece is to execute the route using Shell’s navigation service and pass along a greeting message.

await (App.Current.MainPage as Shell).GoToAsync(new ShellNavigationState(new Uri("app://microsoft.com/newapp/greeting?msg=Hello")));

That’s a long version to show the parts, but you can do less.

(App.Current.MainPage as Shell).GoToAsync("app:///newapp/greeting?msg=Hello");

In the near future Shell will expose the current Shell statically to make it more convenient. Notice that example also omits the host segment.

QueryProperty

To pass the message we can use querystring parameters. This is useful for small bits of data. You can then connect that parameter to a property on  ContentPage or BindingContext (e.g. a view model) using the QueryProperty attribute like this:

namespace NewApp.Pages
{
    [QueryProperty("Message", "msg"]
    public partial class GreetingPage : ContentPage
    {
        public GreetingPage()
        {
            InitializeComponent();
        }

        string _message;
        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
            }
        }
    }
}

The QueryProperty takes the property name (destination) and the query parameter name (source), and Shell navigation sets the value before the page appears. We think this will be very useful and powerful, and look forward to your feedback as you explore using it.

Samples and Resources

For more details about Shell’s powerful new navigation, plus styling the app, customizing the flyout and menu items, setting up bottom tabs and or bottom tabs, and more, check out the new Tailwind Traders mobile app (pictured above) and these resources:

Visual: Creating Consistent Design Across Platforms

It’s possible today to create beautiful native applications for both Android and iOS using Xamarin.Forms. You can even get them to look much the same with styles, effects, custom renderers, and a generous allotment of time. Visual aims to make this much, much easier by providing a consistent control theme by default. Currently, Visual supports the Material Design styling published by Google. Xamarin.Forms 4.0-pre1 today includes the base implementations for Button, Entry, Frame, and ProgressBar. You’ll notice in the screen below that Android and iOS do look quite similar, and all that has been done is to set Visual=”Material” on the ContentPage . With that, Xamarin.Forms will choose alternate renderers that go much deeper than styles to achieve consistency of both design and experience.

More controls and more work to unify layout and design are yet to come before Visual is really ready for production use. This is just a first glimpse, so please join us on this journey. At the moment we are focused exclusively on Google’s Material Design, but we are looking at other design languages to support in the future including Fluent, Fabric, and Cupertino.

For more information about getting started with Visual, check out our preview documentation.

CollectionView: Fast and Flexible Lists

You have told us you want to use modern native list controls for performance, and for more flexibility of layout and interaction. The answer to that is the all new CollectionView. In a future blog post we’ll provide a deeper dive into this control, but for now here’s how you can quickly get started. As before with Shell and Visual, enable CollectionView using the feature flag “CollectionView_Experimental”. Now you’re ready to add the control to your layout like below:

<StackLayout Margin="5">
    <Label HorizontalOptions="Fill" HorizontalTextAlignment="Center" 
            Text="Find the perfect space for your project." TextColor="{StaticResource ThemeColor}"></Label>

    <SearchBar x:Name="Search" HorizontalOptions="Center" BackgroundColor="White" TextColor="{StaticResource ThemeColor}" 
                PlaceholderColor="{StaticResource ThemeColor}" Placeholder="Search"></SearchBar>

    <CollectionView x:Name="Spaces" Margin="0,5,0,0">
        <CollectionView.ItemsLayout>
            <GridItemsLayout Span="2" Orientation="Vertical" />
        </CollectionView.ItemsLayout>
        <CollectionView.EmptyView>
            <StackLayout> 
                <Label FontAttributes="Bold" FontSize="18" Margin="10,25,10,10"
                        HorizontalOptions="Fill" HorizontalTextAlignment="Center" 
                        Text="No results matched your filter."></Label>
                <Label FontAttributes="Italic" FontSize="12" 
                        HorizontalOptions="Fill" HorizontalTextAlignment="Center"
                        Text="Maybe try a broader filter?"></Label>
            </StackLayout>
        </CollectionView.EmptyView>
    </CollectionView>
</StackLayout>

Four layout combinations are supported by default:

  • GridItemsLayout Horizontal
  • GridItemsLayout Vertical
  • ListItemsLayout Horizontal
  • ListItemsLayout Vertical

You may also supply a custom layout, but that’s a more advanced topic for later.

Notice this example also demonstrates the use of an EmptyView which will be visible anytime the ItemSource is empty. For a quick look at CollectionView and its child CarouselView in action, explore the TeamBuilder demo app on GitHub and our preview documentation.

And More

This new release also includes other work that you’ll see very soon in the next stable release of Xamarin.Forms, version 3.5.0. Take for example BindableLayout which enhances any layout to accept a binding source and an item template. In the example below you can use a StackLayout within a ScrollView to make a horizontally scrolling list of items.

<ScrollView VerticalScrollBarVisibility="Never"
            HorizontalScrollBarVisibility="Always">
    <StackLayout BindableLayout.ItemsSource="{Binding ItemsSource}"
                 BindableLayout.ItemTemplateSelector="{StaticResource ItemTemplateSelector}"
                 Orientation="Horizontal"
                 Spacing="7"
                 Padding="10, 5" />
</ScrollView>

That’s not the only enhancement coming your way in the next version of 3.x. For a sneak peek at that, read the full release notes for 4.0.

What’s Up Ahead

The path to feature completeness and a stable release of each feature listed here may be different. We are grouping them into the 4.0 release as our goal is to ship them together in the Spring of 2019 alongside with the stable release of Visual Studio 2019. These key features are each behind the feature flags we described above. Because of this, these features will also ship inside each stable releases of 3.x which will continue delivering to you a steady stream of improvements on our current 6-week release cadence. It will be at your discretion if you feel any of these features are useful enough to be part of your applications prior to the 4.0 stable release. When Xamarin.Forms 4.0 is released stable, we expect to remove these feature flag guards.

To track the progress of each feature please engage with us on GitHub below. Consider also completing our 4.0 feature feedback survey. We will renew the survey for each preview of 4.0 we share.

 

 

 

 

 

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Shimmy Weitzhandler 0

    Shell is worthless without UWP support.

Feedback usabilla icon