Xamarin.Forms.Shell Spec

Created on 10 Apr 2018  ·  199Comments  ·  Source: xamarin/Xamarin.Forms

Xamarin.Forms Shell Spec

Make it simple and straightforward for new developers to get a complete app experience that is properly structured, uses the right elements, with very little effort and a clear path to being good by default.

Shell is an opinionated API at points, it does not always default every value to some .Default which may change based on the running platform. Instead it may set a value which is then respected across all platforms regardless what the platform default is.

Note: Drawing Spec moved to: #2452

Visual Treatment

Needs screenshots...

Shell Hierarchy

Understanding the Shell hierarchy at first can seem overwhelming at first. It represents a complex hierarchy and provides powerful mechanisms for minimizing the amount of boilerplate xaml required to create rich hierarchies.

Thus when first learning shell it is easiest to learn without the shortcuts first, and then introduce the shortcuts to see how to easily minimize the amount of XAML being written.

Note that all samples that follow do not use templated ShellContent's, which are discussed elsewhere in the spec. Failure to properly use ShellContents with a ContentTemplate will result in all pages being loaded at startup, which will negatively impact startup performance. These samples are for learning purposes only.

Fortunately using ShellContents with ContentTemplates is usually more concise than not using them.

No shortcuts

Many of these samples will look needlessly complex, and in reality they are. In the next section these will get simplified.

A simple one page app

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <ShellItem>
    <ShellSection>
      <ShellContent>
        <local:HomePage />
      </ShellContent>
    </ShellSection>
  </ShellItem>
</Shell>

step1

The top bar can be hidden entirely by setting Shell.NavBarVisible="false" on the MainPage. The Flyout would also look rather sparse in this mode and is thus disabled in this sample.

Two page app with bottom tabs

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <ShellItem>

    <ShellSection Title="Home" Icon="home.png">
      <ShellContent>
        <local:HomePage />
      </ShellContent>
    </ShellSection>

    <ShellSection Title="Notifications" Icon="bell.png">
      <ShellContent>
        <local:NotificationsPage />
      </ShellContent>
    </ShellSection>

  </ShellItem>
</Shell>

step2

By adding a section ShellSection to the ShellItem another bottom tab appears. Settings the approriate title and icon allows control over the Tab item title and icon.

Two page app with top and bottom tabs

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <ShellItem>

    <ShellSection Title="Home" Icon="home.png">
      <ShellContent>
        <local:HomePage />
      </ShellContent>
    </ShellSection>

    <ShellSection Title="Notifications" Icon="bell.png">

      <ShellContent Title="Recent">
        <local:NotificationsPage />
      </ShellContent>

      <ShellContent Title="Alert Settings">
        <local:SettingsPage />
      </ShellContent>

    </ShellSection>

  </ShellItem>
</Shell>

step3

By adding a second ShellContent to the ShellSection a top tab bar is added and the pages can be flipped between when the bottom tab is selected.

Two page app using flyout navigation

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       x:Class="MyStore.Shell">

  <Shell.FlyoutHeader>
    <local:FlyoutHeader />
  </Shell.FlyoutHeader>

  <ShellItem Title="Home" Icon="home.png">
    <ShellSection>
      <ShellContent>
        <local:HomePage />
      </ShellContent>
    </ShellSection>
  </ShellItem>

  <ShellItem Title="Notifications" Icon="bell.png">
    <ShellSection>
      <ShellContent>
        <local:NotificationsPage />
      </ShellContent>
    </ShellSection>
  </ShellItem>
</Shell>

step4

The flyout is re-enabled in this sample. Here the user can switch between the two pages using the flyout as an intermediary. A header has also been added to look nice.

Using shorthand syntax

Now that all levels of the hierarchy have been shown and breifly explained, it is possible to leave most of the unneeded wrapping out when defining a hierarchy. Shell only ever contains ShellItems which only ever contain ShellSections which in turn only ever contain ShellContents. However there are implicit conversion operators in place to allow for automatic up-wrapping.

A simple one page app

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <local:HomePage />
</Shell>

With implicit wrapping the Page is automatically wrapped all the way up to a ShellItem. It is not needed to write out all the intermiedate layers. The Title and Icon from the Page will be bound up to any implicitly generated parents.

Two page app with bottom tabs

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <ShellItem>
    <local:HomePage Icon="home.png" />
    <local:NotificationsPage Icon="bell.png" />
  </ShellItem>
</Shell>

The pages are now implicitly wrapped up into ShellContent and their own ShellSections. This results in two different tabs being created, just like before.

Two page app with top and bottom tabs

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       FlyoutBehavior="Disabled"
       x:Class="MyStore.Shell">

  <ShellItem>
    <local:HomePage Icon="home.png" />

    <ShellSection Title="Notifications" Icon="bell.png">
        <local:NotificationsPage />
        <local:SettingsPage />
    </ShellSection>
  </ShellItem>
</Shell>

Two page app using flyout navigation

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:MyStore"
       x:Class="MyStore.Shell">

  <Shell.FlyoutHeader>
    <local:FlyoutHeader />
  </Shell.FlyoutHeader>

  <local:HomePage Icon="home.png" />
  <local:NotificationsPage Icon="bell.png" />
</Shell>

Here the implicit wrapping goes all the way up to shell item so there is no need for us to do any wrapping ourselves.

Navigation Model

Push Navigation

All navigation is based on the View’s .Navigation property. Pushes go into the current ShellSection that is displayed. This means in a push event the top tabs will go away and the bottom tabs will remain.

URI Navigation

The Shell can be navigated using the standard Navigation property as discussed above, however shell introduces a far more convenient navigation mechanism.

Navigation URI's are formatted as follows:

[Shell.RouteScheme]://[Shell.RouteHost]/[Shell]/[ShellItem]/[ShellSection]/[ShellContent]/[NavStack1]/[NavStack2]...

All items in the shell hierarchy have a route associated with them. If the route is not set by the developer, the route is generated at runtime. Runtime generated routes are not gauranteed to be stable across different runs of the app and thus are not useful for deep linking.

Handling the Back Button

Since Shell will be in the enviable position of not having to use native controls, all forms of back button overriding can and should be supported.

Proper handling of the back button needs to support the following features:

  • Intercepting interactions and stopping them
  • Replacing the back button with something else
  • Hiding the back button entirely when desired
  • Work for software and hardware buttons

The API needs to be granular to the page level for ease of use, but also be able to be handled further up the stack in a more general level.

Code Samples and API

Samples

<Shell>
  <Shell.FlyoutHeaderTemplate>
    <DataTemplate>
      <Grid>
        <Label Text="{x:Bind HeaderText}" />
      </Grid>
    </DataTemplate>
  </Shell.FlyoutHeaderTemplate>

  // Flyout Item 1
  <ShellItem Title="My music" ItemsSource="{x:Bind MyMusicModels}" TabLocation="Bottom">
    <ShellItem.ItemTemplate>
      <local:MyMusicItemTemplateSelection />
    </ShellItem.ItemTemplate>
  </ShellItem>

  // Flyout Item 2
  <ShellItem Title="Home" Icon="home.png" GroupBehavior="ShowTabs">
    <ShellContent Title="My Friends">
      <local:FriendsPage />
    </ShellContent>
    <local:FeedPage />
    <local:ProfilePage />
  </ShellItem>

  // Flyout Item 3
  <local:SettingsPage />

  // Flyout Item 4
  <MenuItem Text="Log Out" Command="{x:Bind LogOutCommand}" />
</Shell>

Single Page App using Shell

<Shell FlyoutVisibility="Disabled">
  <local:MyPage />
</Shell>

Single Group of Tabs app (no Flyout)

<Shell FlyoutVisibility="Disabled">
  <ShellItem>
    <local:MyPage />
    <local:MySecondPage />
    <local:MyThirdPage />
  </ShellItem>
</Shell>

Multiple pages in flyout with no tabs

<Shell FlyoutVisibility="Disabled">
  <local:MyPage />
  <local:MySecondPage />
  <local:MyThirdPage />
</Shell>

Single Page Searchable App

<Shell FlyoutVisibility="Disabled">
  <local:MyPage />
</Shell>

```csharp
public class MyPage : ContentPage
{
public class MyPageSearchHandler : SearchHandler
{
public MyPageHandler ()
{
SearchBoxVisibility = SearchBoxVisibility.Collapsed;
IsSearchEnabled = true;
Placeholder = "Search me!";
}

protected override async void OnSearchConfirmed (string query)
{
  IsSearching = true;

  await PerformSearch (query);
  UpdateResults ();

  IsSearching = false;
}

protected override void OnSearchChanged (string oldValue, string newValue)
{
  // Do nothing, we will wait for confirmation
}

}

public MyPage ()
{
Shell.SetSearchHandler (this, new MyPageSearchHandler ());
}
}

## API Definition

### Shell
This is the base class for Shell's. It defines a somewhat strict navigational model however all shells must adhere to it in general. It does not include any theming or design language specific features.

```csharp
[ContentProperty("Items")]
public class Shell : Page, IShellController
{
  // Attached Properties
  public static readonly BindableProperty BackButtonBehaviorProperty;
  public static readonly BindableProperty FlyoutBehaviorProperty;
  public static readonly BindableProperty NavBarVisibleProperty;
  public static readonly BindableProperty SearchHandlerProperty;
  public static readonly BindableProperty SetPaddingInsetsProperty;
  public static readonly BindableProperty TabBarVisibleProperty;
  public static readonly BindableProperty TitleViewProperty;
  public static readonly BindableProperty ShellBackgroundColorProperty;
  public static readonly BindableProperty ShellDisabledColorProperty;
  public static readonly BindableProperty ShellForegroundColorProperty;
  public static readonly BindableProperty ShellTabBarBackgroundColorProperty;
  public static readonly BindableProperty ShellTabBarDisabledColorProperty;
  public static readonly BindableProperty ShellTabBarForegroundColorProperty;
  public static readonly BindableProperty ShellTabBarTitleColorProperty;
  public static readonly BindableProperty ShellTabBarUnselectedColorProperty;
  public static readonly BindableProperty ShellTitleColorProperty;
  public static readonly BindableProperty ShellUnselectedColorProperty;

  public static BackButtonBehavior GetBackButtonBehavior(BindableObject obj);
  public static FlyoutBehavior GetFlyoutBehavior(BindableObject obj);
  public static bool GetNavBarVisible(BindableObject obj);
  public static SearchHandler GetSearchHandler(BindableObject obj);
  public static bool GetSetPaddingInsets(BindableObject obj);
  public static bool GetTabBarVisible(BindableObject obj);
  public static View GetTitleView(BindableObject obj);
  public static void SetBackButtonBehavior(BindableObject obj, BackButtonBehavior behavior);
  public static void SetFlyoutBehavior(BindableObject obj, FlyoutBehavior value);
  public static void SetNavBarVisible(BindableObject obj, bool value);
  public static void SetSearchHandler(BindableObject obj, SearchHandler handler);
  public static void SetSetPaddingInsets(BindableObject obj, bool value);
  public static void SetTabBarVisible(BindableObject obj, bool value);
  public static void SetTitleView(BindableObject obj, View value);
  public static Color GetShellBackgroundColor(BindableObject obj);
  public static Color GetShellDisabledColor(BindableObject obj);
  public static Color GetShellForegroundColor(BindableObject obj);
  public static Color GetShellTabBarBackgroundColor(BindableObject obj);
  public static Color GetShellTabBarDisabledColor(BindableObject obj);
  public static Color GetShellTabBarForegroundColor(BindableObject obj);
  public static Color GetShellTabBarTitleColor(BindableObject obj);
  public static Color GetShellTabBarUnselectedColor(BindableObject obj);
  public static Color GetShellTitleColor(BindableObject obj);
  public static Color GetShellUnselectedColor(BindableObject obj);
  public static void SetShellBackgroundColor(BindableObject obj, Color value);
  public static void SetShellDisabledColor(BindableObject obj, Color value);
  public static void SetShellForegroundColor(BindableObject obj, Color value);
  public static void SetShellTabBarBackgroundColor(BindableObject obj, Color value);
  public static void SetShellTabBarDisabledColor(BindableObject obj, Color value);
  public static void SetShellTabBarForegroundColor(BindableObject obj, Color value);
  public static void SetShellTabBarTitleColor(BindableObject obj, Color value);
  public static void SetShellTabBarUnselectedColor(BindableObject obj, Color value);
  public static void SetShellTitleColor(BindableObject obj, Color value);
  public static void SetShellUnselectedColor(BindableObject obj, Color value);

  // Bindable Properties
  public static readonly BindableProperty CurrentItemProperty;
  public static readonly BindableProperty CurrentStateProperty;
  public static readonly BindableProperty FlyoutBackgroundColorProperty;
  public static readonly BindableProperty FlyoutHeaderBehaviorProperty;
  public static readonly BindableProperty FlyoutHeaderProperty;
  public static readonly BindableProperty FlyoutHeaderTemplateProperty;
  public static readonly BindableProperty FlyoutIsPresentedProperty;
  public static readonly BindableProperty GroupHeaderTemplateProperty;
  public static readonly BindableProperty ItemsProperty;
  public static readonly BindableProperty ItemTemplateProperty;
  public static readonly BindableProperty MenuItemsProperty;
  public static readonly BindableProperty MenuItemTemplateProperty;

  public Shell();

  public event EventHandler<ShellNavigatedEventArgs> Navigated;

  public event EventHandler<ShellNavigatingEventArgs> Navigating;

  public ShellItem CurrentItem {get; set;}

  public ShellNavigationState CurrentState {get; }

  public Color FlyoutBackgroundColor {get; set;}

  public FlyoutBehavior FlyoutBehavior {get; set;}

  public object FlyoutHeader {get; set;}

  public FlyoutHeaderBehavior FlyoutHeaderBehavior {get; set;}

  public DataTemplate FlyoutHeaderTemplate {get; set;}

  public bool FlyoutIsPresented {get; set;}

  public DataTemplate GroupHeaderTemplate {get; set;}

  public ShellItemCollection Items {get; }

  public DataTemplate ItemTemplate {get; set;}

  public MenuItemCollection MenuItems {get; }

  public DataTemplate MenuItemTemplate {get; set;}

  public string Route {get; set;}

  public string RouteHost { get; set; }

  public string RouteScheme { get; set; }

  public async Task GoToAsync(ShellNavigationState state, bool animate = true);

  protected virtual void OnNavigated(ShellNavigatedEventArgs args);

  protected virtual void OnNavigating(ShellNavigatingEventArgs args);
}

Description

Attached Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| SearchHandlerProperty | Attached property for the definition of a page level Search capability. Can be attached at multiple points in the hierarchy. Uses some of the features defined here https://material.io/guidelines/patterns/search.html#search-in-app-search |
| BackButtonBehavior | Allows complete override of how the back button behaves. Applies to on-screen and physical back buttons. |
| FlyoutBehavior | Defines how the Flyout should present itself. This can be attached to ShellItems, ShellContents, or Pages to override the default behavior. |
| NavBarVisibleProperty | Property set on a Page to define if the NavBar should be visible when it is presented |
| SetPaddingInsetsProperty | Setting this property on a Page will cause its Padding to be set such that its content will not flow under any Shell chrome. |
| TabBarVisibleProperty | Property set on a Page to define if the TabBar should be visible when it is presented |
| TitleViewProperty | Property set on a Page to define the TitleView |
| ShellBackgroundColorProperty | Describes the background color which should be used for the chrome elements of the Shell. This color will not fill in behind the Content of the Shell. |
| ShellDisabledColorProperty | The color to shade text/icons which are disabled |
| ShellForegroundColorProperty | The color to shade normal text/icons in the shell |
| ShellTabBarBackgroundColorProperty | Override of ShellBackgroudnColor for the TabBar. If not set ShellBackgroundColor will be used |
| ShellTabBarDisabledColorProperty | Override of ShellDisabledColor for the TabBar. If not set ShellDisabledColorProperty will be used |
| ShellTabBarForegroundColorProperty | Override of ShellForegroundColorProperty for the TabBar. If not set ShellForegroundColorProperty will be used |
| ShellTabBarTitleColorProperty | Override of ShellTitleColorProperty for the TabBar. If not set ShellTitleColorProperty will be used |
| ShellTabBarUnselectedColorProperty | Override of ShellUnselectedColorProperty for the TabBar. If not set ShellUnselectedColorProperty will be used |
| ShellTitleColorProperty | The color used for the title of the current Page |
| ShellUnselectedColorProperty | The color used for unselected text/icons in the shell chrome |

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| CurrentItem | The currently selected ShellItem |
| CurrentState | The current navigation state of the Shell. Passing this state back to GoToAsync will cause the Shell to return to navigate back state. |
| FlyoutBackgroundColorProperty | The background color of the Flyout menu |
| FlyoutBehavior | Sets the default FlyoutBehavior for the Shell. |
| FlyoutHeader | The object used as the Header of the Flyout. If FlyoutHeaderTemplate is not null, this is passed as the BindingContext to the inflated object. If FlyoutHeaderTemplate is null and FlyoutHeader is of type View it will be used directly. Otherwise it will be shown by calling ToString() and displaying the result. |
| FlyoutHeaderBehavior | Sets the behavior of the FlyoutHeader when the Flyout needs to be scrolled to show contents. |
| FlyoutHeaderTemplate | The template used to create a header for the Flyout. |
| FlyoutIsPresented | Gets or sets whether or not the Flyout is current visible |
| GroupHeaderTemplate | The DataTemplate used to show a Group Header if a ShellItem requests to be displayed as a Group of Tabs in the Flyout. If null, no header is displayed. |
| Items | The primary Content of a Shell. Items define the list of items that will show in the Flyout as well as the content that will be displayed when a sidebar item is selected. |
| ItemTemplate | The DataTemplate used to show items from the Items collection in the Flyout. Allows the developer to control visuals in the Flyout. |
| MenuItems | A collection of MenuItems which will show up in the flyout in their own section. |
| MenuItemTemplate | The DataTemplate to use when displayed a MenuItem in the Flyout. |
| Route | The route part to address this element when performing deep linking. |
| RouteHost | The string to place in the host portion of the URI generated when creating deep-links |
| RouteScheme | The string to place in the scheme portion of the URI generated when creating deep-links |

Public Methods:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| GoToAsync | Navigate to a ShellNavigationState. Returns a Task which will complete once the animation has completed. |

Public Events:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Navigating | The Shell is about to perform a Navigation either due to user interaction or the developer calling an API. The developer may cancel Navigation here if possible. |
| Navigated | The Shell has completed a Navigation event. |

ShellItemCollection

A collection for ShellItems

public sealed class ShellItemCollection : IEnumerable<ShellItem>, IList<ShellItem>

MenuItemCollection

A collection for MenuItems

public sealed class MenuItemCollection : IEnumerable<MenuItem>, IList<MenuItem>

ShellSectionCollection

A collection for ShellSections

public sealed class ShellSectionCollection : IEnumerable<ShellSection>, IList<ShellSection>

ShellContentCollection

A collection for ShellContents

public sealed class ShellContentCollection : IEnumerable<ShellContent>, IList<ShellContent>

ShellNavigatingEventArgs

An EventArgs used to describe a navigation event which is about to occur. The ShellNavigationEventArgs may also be used to cancel the navigation event if the developer desires.

public class ShellNavigatingEventArgs : EventArgs
{
  public ShellNavigationState Current { get; }

  public ShellNavigationState Target { get; }

  public ShellNavigationSource Source { get; }

  public bool CanCancel { get; }

  public bool Cancel ();
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Current | The current NavigationState of the Shell. Calling GoToAsync with this ShellNavigationState will effectively undo this navigation event. |
| Target | The state the Shell will be in after this navigation event completes. |
| Source | The type of navigation which occurred to trigger this event. There may be multiple flags set. |
| CanCancel | Whether or not the navigation event is cancellable. Not all events can be cancelled. |

Public Methods:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Cancel | Cancels the current navigation event. Returns true if the cancellation was succesful. |

ShellNavigatedEventArgs

public class ShellNavigatedEventArgs : EventArgs
{
  public ShellNavigationState Previous { get; }

  public ShellNavigationState Current { get; }

  public ShellNavigationSource Source { get; }
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Previous | The prior NavigationState of the Shell. |
| Current | The new state the Shell is in when this navigation event completed. |
| Source | The type of navigation which occurred to trigger this event. There may be multiple flags set. |

ShellNavigationState

public class ShellNavigationState
{
  public Uri Location { get; set; }

  public ShellNavigationState ();
  public ShellNavigationState (string location);
  public ShellNavigationState (Uri uri);

  public static implicit operator ShellNavigationState (Uri uri);
  public static implicit operator ShellNavigationState (String value);
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Location | The Uri which describes the navigation state of the Shell |

Constructors:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| (void) | Creates a new ShellNavigationState with a null Location |
| (String) | Creates a new ShellNavigationState with the Location set to the supplied string |
| (Uri) | Creates a new ShellNavigationState with the Location set to the supplied Uri |

ShellNavigationSource

[Flags]
public enum ShellNavigationSource
{
  Unknown = 0,
  Push,
  Pop,
  PopToRoot,
  Insert,
  Remove,
  ShellItemChanged,
  ShellSectionChanged,
  ShellContentChanged,
}

BaseShellItem

public class BaseShellItem : NavigableElement
{
  public static readonly BindableProperty FlyoutIconProperty;
  public static readonly BindableProperty IconProperty;
  public static readonly BindableProperty IsCheckedProperty;
  public static readonly BindableProperty IsEnabledProperty;
  public static readonly BindableProperty TitleProperty;

  public ImageSource FlyoutIcon { get; set; }

  public ImageSource Icon { get; set; }

  public bool IsChecked { get; }

  public bool IsEnabled { get; set; }

  public string Route { get; set; }

  public string Title { get; set; }
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| FlyoutIcon | The default icon to use when displayed in the Flyout. Will default to Icon if not set. |
| Icon | The icon to display in parts of the chrome which are not the Flyout. |
| IsChecked | If the BaseShellItem is currently checked in the Flyout (and thus should be highlighted) |
| IsEnabled | If the the BaseShellItem is selectable in the chrome |
| Route | Equivelant to setting Routing.Route |
| Title | The Title to display in the UI |

ShellGroupItem

public class ShellGroupItem : BaseShellItem
{
  public static readonly BindableProperty FlyoutDisplayOptionsProperty;;

  public FlyoutDisplayOptions FlyoutDisplayOptions { get; set; }
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| FlyoutDisplayOptions | Controls how this item and its children are displayed in the flyout |

ShellItem

[ContentProperty("Items")]
public class ShellItem : ShellGroupItem, IShellItemController, IElementConfiguration<ShellItem>
{
  public static readonly BindableProperty CurrentItemProperty;

  public ShellItem();

  public ShellSection CurrentItem { get; set; }

  public ShellSectionCollection Items;

  public static implicit operator ShellItem(ShellSection shellSection);

  public static implicit operator ShellItem(ShellContent shellContent);

  public static implicit operator ShellItem(TemplatedPage page);

  public static implicit operator ShellItem(MenuItem menuItem);
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| CurrentItem | The selected ShellSection. |
| Items | The ShellSectionCollection which is the primary content of a ShellItem. This collection defines all the tabs within a ShellItem. |

ShellSection

[ContentProperty("Items")]
public class ShellSection : ShellGroupItem, IShellSectionController
{
  public static readonly BindableProperty CurrentItemProperty;
  public static readonly BindableProperty ItemsProperty

  public ShellSection();

  public ShellContent CurrentItem { get; set; }

  public ShellContentCollection Items { get; }

  public IReadOnlyList<Page> Stack { get; }

  public static implicit operator ShellSection(ShellContent shellContent);

  public virtual async Task GoToAsync(List<string> routes, IDictionary<string, string> queryData, bool animate);

  protected virtual IReadOnlyList<Page> GetNavigationStack();

  protected virtual void OnInsertPageBefore(Page page, Page before);

  protected async virtual Task<Page> OnPopAsync(bool animated);

  protected virtual async Task OnPopToRootAsync(bool animated);

  protected virtual Task OnPushAsync(Page page, bool animated);

  protected virtual void OnRemovePage(Page page);
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| CurrentItem | The selected ShellContent of the ShellSection. |
| Items | The ShellContentCollection which is the root content of the ShellSection. |
| Stack | The current pushed navigation stack on the ShellSection. |

Methods:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| GoToAsync | Used by deep-linking to navigate to a known location. Should not need to be called directly in most cases. |
| GetNavigationStack | Returns the current navigation stack |
| OnInsertPageBefore | Called when the INavigation interfaces InsertPageBefore method is called |
| OnPopAsync | Called when the INavigation interfaces PopAsync method is called |
| OnPopToRootAsync | Called when the INavigation interfaces PopToRootAsync method is called |
| OnPushAsync | Called when the INavigation interfaces PushAsync method is called |
| OnRemovePage | Called when the INavigation interfaces RemovePage method is called |

ShellContent

[ContentProperty("Content")]
public class ShellContent : BaseShellItem, IShellContentController
{
  public static readonly BindableProperty ContentProperty;
  public static readonly BindableProperty ContentTemplateProperty;
  public static readonly BindableProperty MenuItemsProperty;

  public ShellContent();

  public object Content { get; set; }

  public DataTemplate ContentTemplate { get; set; }

  public MenuItemCollection MenuItems { get; }

  public static implicit operator ShellContent(TemplatedPage page);
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Content | The Content of a ShellContent. Usually a ContentPage or the BindingContext of the Page inflated by the ContentTemplate |
| ContentTemplate | Used to dynamically inflate the content of the ShellContent. The Content property will be set as the BindingContext after inflation. |
| MenuItems | The items to display in the Flyout when this ShellContent is the presented page |

SearchHandler

public class SearchHandler : BindableObject, ISearchHandlerController
{
  public static readonly BindableProperty ClearIconHelpTextProperty;
  public static readonly BindableProperty ClearIconNameProperty;
  public static readonly BindableProperty ClearIconProperty;
  public static readonly BindableProperty ClearPlaceholderCommandParameterProperty;
  public static readonly BindableProperty ClearPlaceholderCommandProperty;
  public static readonly BindableProperty ClearPlaceholderEnabledProperty;
  public static readonly BindableProperty ClearPlaceholderHelpTextProperty;
  public static readonly BindableProperty ClearPlaceholderIconProperty;
  public static readonly BindableProperty ClearPlaceholderNameProperty;
  public static readonly BindableProperty CommandParameterProperty;
  public static readonly BindableProperty CommandProperty;
  public static readonly BindableProperty DisplayMemberNameProperty;
  public static readonly BindableProperty IsSearchEnabledProperty;
  public static readonly BindableProperty ItemsSourceProperty;
  public static readonly BindableProperty ItemTemplateProperty;
  public static readonly BindableProperty PlaceholderProperty;
  public static readonly BindableProperty QueryIconHelpTextProperty;
  public static readonly BindableProperty QueryIconNameProperty;
  public static readonly BindableProperty QueryIconProperty;
  public static readonly BindableProperty QueryProperty;
  public static readonly BindableProperty SearchBoxVisibilityProperty;
  public static readonly BindableProperty ShowsResultsProperty;

  public ImageSource ClearIcon { get; set; }

  public string ClearIconHelpText { get; set; }

  public string ClearIconName { get; set; }

  public ICommand ClearPlaceholderCommand { get; set; }

  public object ClearPlaceholderCommandParameter { get; set; }

  public bool ClearPlaceholderEnabled { get; set; }

  public string ClearPlaceholderHelpText { get; set; }

  public ImageSource ClearPlaceholderIcon { get; set; }

  public string ClearPlaceholderName { get; set; }

  public ICommand Command { get; set; }

  public object CommandParameter { get; set; }

  public string DisplayMemberName { get; set; }

  public bool IsSearchEnabled { get; set; }

  public IEnumerable ItemsSource { get; set; }

  public DataTemplate ItemTemplate { get; set; }

  public string Placeholder { get; set; }

  public string Query { get; set; }

  public ImageSource QueryIcon { get; set; }

  public string QueryIconHelpText { get; set; }

  public string QueryIconName { get; set; }

  public SearchBoxVisiblity SearchBoxVisibility { get; set; }

  public bool ShowsResults { get; set; }

  protected virtual void OnClearPlaceholderClicked();

  protected virtual void OnItemSelected(object item);

  protected virtual void OnQueryChanged(string oldValue, string newValue);

  protected virtual void OnQueryConfirmed();
}

Properties:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| ClearIconHelpText | The accessible help text for the clear icon |
| ClearIconNameProperty | The name of the clear icon for usage with screen readers |
| ClearIcon | The icon displayed to clear the contents of the search box. |
| ClearPlaceholderCommandParameter | The paramter for the ClearPlaceholderCommand |
| ClearPlacehodlerCommand | The command to execute when the ClearPlaceholder icon is tapped |
| ClearPlaceholderEnabled | The enabled state of the ClearPlaceholderIcon. Default is true. |
| ClearPlaceholderHelpText | The accessible help text for the clear placeholder icon |
| ClearPlaceholderIcon | The icon displayed in the ClearIcon location when the search box is empty. |
| ClearPlaceholderName | The name of the clear placeholder icon for usage with screen readers |
| CommandParameter | The parameter for the Command |
| Command | The ICommand to execute when a query is confirmed
| DisplayMemberPath | The name or path of the property that is displayed for each the data item in the ItemsSource. |
| IsSearchEnabled | Controls the enabled state of the search box. |
| ItemsSource | A collection of items to display in the suggestion area. |
| ItemTemplate | A template for the items displayed in the suggestion area. |
| Placeholder | A string to display when the search box is empty. |
| QueryIconHelpTextProperty | The accessible help text for the query icon |
| QueryIconNameProperty | The name of the query icon for usage with screen readers |
| QueryIcon | The icon used to indicate to the user that search is available |
| Query | The current string in the search box. |
| SearchBoxVisibility | Defines the visibility of the search box in the Shells chrome. |
| ShowsResults | Determines if search results should be expected on text entry |

Protected Methods:

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| OnClearPlaceholderClicked | Called whenever the ClearPlaceholder icon has been pressed. |
| OnItemSelected | Called whenever a search result is pressed by the user |
| OnQueryConfirmed | Called whenever the user pressed enter or confirms their entry in the search box. |
| OnQueryChanged | Called when the Query is changed. |

SearchBoxVisiblity

public enum SearchBoxVisiblity
{
  Hidden,
  Collapsable,
  Expanded
}

| Value | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Hidden | The search box is not visible or accessible. |
| Collapsable | The search box is hidden until the user performs an action to reveal it. |
| Expanded | The search box is visible as a fully expanded entry. |

BackButtonBehavior

public class BackButtonBehavior : BindableObject
{
  public ImageSource IconOverride { get; set; }
  public string TextOverride { get; set; }
  public ICommand Command { get; set; }
  public object CommandParameter { get; set; }
}

| API | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| IconOverride | Changes the Icon used for the back button. |
| TextOverride | Changes the Text used to indicate backwards navigation if text is used. |
| Command | Provides a replacement command to invoke when the back button is pressed. |
| CommandParameter | The command parameter used with Command |

FlyoutDisplayOptions

Determines how the ShellGroupItem should display in the FlyoutMenu.

  public enum FlyoutDisplayOptions
  {
    AsSingleItem,
    AsMultipleItems,
  }

| Value | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| AsSingleItem | The ShellGroupItem will be visible as a single entry in the Flyout. |
| AsMultipleItems | The ShellGroupItem will be visible as a group of items, one for each child in the Flyout. |

FlyoutHeaderBehavior

Controls the behavior of the FlyoutHeader when scrolling.

public enum FlyoutHeaderBehavior {
  Default,
  Fixed,
  Scroll,
  CollapseOnScroll,
}

| Value | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Default | Platform default behavior. |
| Fixed | Header remains visible and unchanged at all times |
| Scroll | Header scrolls out of view as user scrolls menu |
| CollapseOnScroll | Header collapses to title only as user scrolls |

FlyoutBehavior

public enum FlyoutBehavior
{
  Disabled,
  Flyout,
  Locked
}

| Value | Description |
| -----------| ----------------------------------------------------------------------------------------------|
| Disabled | The flyout cannot be acccessed by the user. |
| Flyout | The Flyout is works as a normal flyout which can be open/closed by the user. |
| Locked | The Flyout is locked out and cannot be closed by the user, it does not overalp content. |

DataTemplateExtension

This extension quickly converts a type into a ControlTemplate. This is useful for instances where the template would otherwise be specified as

<ListView>
  <ListView.ItemTemplate>
    <DataTemplate>
      <local:MyCell />
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

This can then be condensed down to

<ListView ItemTemplate="{DataTemplate local:MyCell}" />
public sealed class ControlTemplateExtension : IBindingExtension<ControlTemplate>
public sealed class DataTemplateExtension : IBindingExtension<DataTemplate>

Odds and Ends

What happens when you select a tab in Flyout which has been pushed to?

This is the equivalent of focusing the tab and calling PopToRoot on it.

What happens when I switch ShellItems and there are items on the backstack of a ShellContent of the old ShellItem

If the old ShellItem is templated, the back stack is lost. If the ShellItem is not templated the BackStack stays intact and when switching back to the old ShellItem the backstack will be properly reflected. Switching back may clear the backstack however as indicated in the above answer.

Effecient loading of pages

A major problem with using the Shell is the ease by which a user can end up loading all pages at the start of their application run. This large frontloaded allocation can result in quite poor startup performance if a large number of content pages are needed. In order to fix this templating should be employed when possible.

Templated ShellContents

Templating shell tab items is the most granular form of templating available, it is fortunately also the easiest to do. Take the following shell.

<?xml version="1.0" encoding="utf-8" ?>
<MaterialShell xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:local="clr-namespace:MyStore"
               x:Class="MyStore.Shell">

  <ShellItem Title="My apps &amp; games">
    <local:UpdatesPage />
    <local:InstalledPage />
    <local:LibraryPage />
  </ShellItem>

  <ShellItem GroupBehavior="ShowTabs">
    <local:HomePage />
    <local:GamesPage />
    <local:MoviesTVPage />
    <local:BooksPage />
    <local:MusicPage />
    <local:NewsstandPage />
  </ShellItem>
</MaterialShell>

When this Shell loads, all 9 pages will be inflated at once. This is because no templating is employed. To employ basic templating we can convert this into:

<?xml version="1.0" encoding="utf-8" ?>
<MaterialShell xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:local="clr-namespace:MyStore"
               x:Class="MyStore.Shell">

  <ShellItem Title="My apps &amp; games">
    <ShellContent Title="Updates"        Icon="updates.png" ContentTemplate="{DataTemplate local:UpdatesPage}" />
    <ShellContent Title="Installed Apps" Icon="apps.png"    ContentTemplate="{DataTemplate local:InstalledPage}" />
    <ShellContent Title="Library"        Icon="library.png" ContentTemplate="{DataTemplate local:LibraryPage}" />
  </ShellItem>

  <ShellItem GroupBehavior="ShowTabs">
    <ShellContent Title="Home"          Icon="updates.png"   ContentTemplate="{DataTemplate local:HomePage}" />
    <ShellContent Title="Games"         Icon="games.png"     ContentTemplate="{DataTemplate local:GamesPage}" />
    <ShellContent Title="Movies and TV" Icon="moviesTV.png"  ContentTemplate="{DataTemplate local:MoviesTVPage}" />
    <ShellContent Title="Books"         Icon="books.png"     ContentTemplate="{DataTemplate local:BooksPage}" />
    <ShellContent Title="Music"         Icon="music.png"     ContentTemplate="{DataTemplate local:MusicPage}" />
    <ShellContent Title="Newsstand"     Icon="newsstand.png" ContentTemplate="{DataTemplate local:NewsstandPage}" />
  </ShellItem>
</MaterialShell>

Pages are now only loaded as needed and can be unloaded as needed as well. If needed the ShellItem's themselves can also be templated with a collection and a DataTemplateSelector which prevents even the ShellContents from having to be loaded eagerly, however this is largely unneeded and templating ShellItem is more useful for Shells that have ShellItems with large numbers of otherwise similar tabs. Templating the ShellContent should be the key area to provide templating for performance concerns.

Reconstructing the Google Play Store User Interface

Please note this is not intended to be a demo of the best way to code an application, but really the most concise format to shove together the UI for GPS. It also makes no attempt to virtualize the relevant pages by using ViewModels and DataTemplateSelector's. This means this would be quite bad performing as all pages would be loaded at app start. Reader is warned.

All page content is assumed to be working right, this is only to get the general idea of the chrome.

Shell.xaml

A proper implementation of this would use ShellItems for every page and set the ItemsSource and ItemTemplate. This would allow each page to only be loaded once it is needed and unloaded when no longer needed.

<?xml version="1.0" encoding="utf-8" ?>
<MaterialShell xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:local="clr-namespace:MyStore"
               x:Class="MyStore.Shell"
               FlyoutHeaderBehavior="Fixed"
               FlyoutHeader="{x:Bind HeaderViewModel}">
  <MaterialShell.FlyoutHeaderTemplate>
    <local:CircleImageAndLabelControl HeightRequest="350" />
  </MaterialShell.FlyoutHeaderTempalte>

  <ShellItem Title="My apps &amp; games">
    <ShellItem.ShellAppearance>
      <MaterialShellAppearance NavBarCollapseStyle="Full">
    </ShellItem.ShellAppearance>
    <local:UpdatesPage />
    <local:InstalledPage />
    <local:LibraryPage />
  </ShellItem>

  <local:NotificationsPage Title="My notifications" />

  <local:SubscriptionsPage />

  <ShellItem GroupBehavior="ShowTabs">
    <ShellItem.ShellAppearance>
      <MaterialShellAppearance NavBarCollapseStyle="Full" TabBarCollapseStyle="Full" UseSwipeGesture="false">
    </ShellItem.ShellAppearance>
    <local:HomePage />
    <local:GamesPage />
    <ShellContent Title="Movies &amp; TV" Icon="moviesTV.png" ContentTemplate="{DataTemplate local:MoviesTVPage}">
      <ShellContent.MenuItems>
        <MenuItem Title="Open Movies &amp; TV app" Command="{xBind MoviesTVAppCommand}" />
      </ShellContent.MenuItems>
    </ShellContent>
    <ShellContent Title="Books" Icon="books.png" ContentTemplate="{DataTemplate local:BooksPage}">
      <ShellContent.MenuItems>
        <MenuItem Title="Open Books app" Command="{xBind BooksAppCommand}" />
      </ShellContent.MenuItems>
    </ShellContent>
    <ShellContent Title="Music" Icon="music.png" ContentTemplate="{DataTemplate local:MusicPage}">
      <ShellContent.MenuItems>
        <MenuItem Title="Open Music app" Command="{xBind MusicAppCommand}" />
      </ShellContent.MenuItems>
    </ShellContent>
    <ShellContent Title="Newsstand" Icon="newsstand.png" ContentTemplate="{DataTemplate local:NewsstandPage}">
      <ShellContent.MenuItems>
        <MenuItem Title="Open Newsstand app" Command="{xBind NewsstandAppCommand}" />
      </ShellContent.MenuItems>
  </ShellItem>

  <local:AccountPage />

  <MenuItem Title="Redeem" Icon="redeem.png" Command="{x:Bind RedeemCommand}" />

  <local:WishlistPage />

  <MenuItem Title="Play Protect" Icon="protect.png" Command="{x:Bind NavigateCommand}" CommandParameter="ProtectPage" />

  <MenuItem Title="Settings" Icon="settings.png" Command="{x:Bind SettingsCommand}" CommandParameter="SettingsPage" />

  <MaterialShell.MenuItems>
    <MenuItem Title="Help &amp; feedback" Command="{x:Bind NavigateCommand}" CommandParameter="HelpPage" />
    <MenuItem Title="Parent Guide" Command="{x:Bind NavigateCommand}" CommandParameter="ParentPage" />
    <MenuItem Title="Help &amp; feedback" Command="{x:Bind UrlCommand}" CommandParameter="http://support.google.com/whatever" />
  </MaterialShell.MenuItems>
</MaterialShell>

The store pages

<?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:MyStore"
             x:Class="MyStore.HomePage"
             Title="Home"
             Icon="home.png"
             ShellAppearance.BackgroundColor="Green">
  <Label Text="Home content here" />
</ContentPage>
<?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:MyStore"
             x:Class="MyStore.MoviesTVPage"
             Title="Movies &amp; TV"
             Icon="movies.png"
             ShellAppearance.BackgroundColor="Red">
  <Label Text="Movies and TV content here" />
</ContentPage>

And to add the search bar.

public class HomePage : ContentPage
{
  public class HomeSearchHandler : SearchHandler
  {
    public HomeSearchHandler ()
    {
      SearchBoxVisibility = SearchBoxVisibility.Expanded;
      IsSearchEnabled = true;
      Placeholder = "Google Play";
      CancelPlaceholderIcon = "microphone.png"
    }

    protected override void OnSearchConfirmed (string query)

{      // Navigate to search results page here
    }

    protected override void OnSearchChanged (string oldValue, string newValue)
    {
    }

    protected override void OnCancelPlaceholderPressed ()
    {
      // Trigger voice API here
    }
  }

  public HomePage
  {
    Shell.SetSearchHandler (this, new HomeSearchHandler ());
  }  
}

And so on and so on setting the colors and the content correctly.

For pages like the Settings page where the flyout should not be accessible until the back button is pressed:

<?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:MyStore"
             x:Class="MyStore.SettingsPage"
             Title="Settings"
             Icon="settings.png"
             ShellAppearance.BackgroundColor="Grey"
             MaterialShell.FlyoutBehavior="Disabled">
  <Label Text="Settings content here" />
</ContentPage>

TODO

  • [x] Add API for search box
  • [x] Add API for ContentSafeArea handling
  • [x] Add API for floating menu
  • [x] Add API for window menu items
  • [x] Add API for snackbar
  • [x] Add API for navigation interruption
  • [x] Add API for bottom sheet
  • [x] Add API to position FAB
  • [x] Add stories to make navigation ideas clearer (partially done)
  • [x] Add LeftBarButton style API
  • [x] Add mechanism for getting Back Stack from ShellContent
  • [x] Add API for changing color of the ribbon based on selected tab
  • [x] Add optional suggestion support for SearchHandler
  • [x] Add support for configuring always expanded search bar vs search bar as icon
  • [x] Add API for getting the "Current" page from the MaterialShell class. Needed for some navigation scenarios.
  • [x] Add API for saving "states" to the back stack
  • [x] Add API to block flyout from coming out
  • [x] Add API for "submenu" items for ShellContent's ala GPS -> Music -> Open Music app
  • [x] Add API for CancelPlaceholder Command and Icon (usually used for microphone icon for voice search)
  • [x] Segue API
  • [x] Work out what to do with INavigation
  • [ ] Expand Bottom Sheet API to match Google Maps capabilities
  • [x] API to handle Flyout presentation
  • [ ] API to disable Flyout gesture when needed
  • [ ] Large title API
  • [ ] Transitions API

Issues

ISearchHandler [FIXED]

There is a lot this interface is doing and worse it's probably going to need to be expanded as time goes on. Therefor it stands to reason that it should probably instead be an abstract base class the user can implement. This unfortunate means yet another object allocation. However it maintains flexibility in the future. It is likely this change will happen.

Floating Menu

The attachment API is a bit heavy and perhaps too confusing for users. Worse it might not map very well to all platforms to make sure the attachment works with animations. More work is required to validate this API.

shell enhancement ➕

Most helpful comment

Folks, yesterday Jason and myself had a discussion on how to improve this spec and we will be doing a large update, we are splitting this into different issues.

All 199 comments

Let's get this conversation humming, because we really need to hear from you, our community of developers!

FIRST, thanks @jassmith for laboring to capture this and craft a proposal for us to discuss in the open here.

I'm going to share some of my thoughts, ask some stupid questions, and ask some hopefully-not-too-leading questions. As the Program Manager for Xamarin.Forms I often have to ask questions in such a way that it makes it sounds like I don't have a clue (sometimes I don't), but really I just need to hear things from YOU without putting words in your mouth.

There are things I like in this proposal, because I can see how they might address some the problems I've been talking to many, many of you about, and we are working towards solving.

I also have reservations.

I'll kick off here with a couple general threads of thought about the Shell concept and the developer experience.

App Experience

to get a complete app experience that is properly structured, uses the right elements, with very little effort and a clear path to being good by default.

If I use this approach to describe my application at the top level, I get:

  • an app themed to look the same on every platform
  • material design (in this case) patterns on by default
  • the latest navigation patterns enabled with configuration
  • I don't have to labor to customize Entry or Button to look the same on iOS and Android and UWP?

Is that accurate? Other benefits I should highlight?

Instead of App I have MaterialShell. I need to learn/adopt a new top level application paradigm to benefit from this?

Once I'm into my app, I'm back in ContentPage land, correct? But all my Buttons and Entrys are material-fied and pretty. Can I still OnPlatform and the like to diverge the look (or behavior) to be different on another platform?

What's my migration path look like from an existing app to using this "shell"? I introduce the new MaterialShell, describe how I want my app to be structure and look, and just run it to see the new goodness?

Customizing

What are my options if I like the way the Flyout or the menu items look, but I need to tweak them to match my designers comps? At what point am I saying "Ugh, I should've rolled this all myself" and moving what I have to a standard Xamarin.Forms app structure?

If I have to totally abandon the MaterialShell, do I lose all that styling goodness and I'm back where I started (like today) with an Entry looking quite different between iOS and Android and UWP? I would like to not.

There's a tipping point I'm anticipating. After I've used this approach to get going quickly, I will hit some limitation and need to explore my options. What are they and at what point am I better off not usingMaterialShell?

The Problem

I'll close this first comment with a few questions to everyone reading.

  • Is the problem that this proposal attempts to address well defined?
  • Is it a problem you share?
  • As you read this spec, what problems that you have faced on previous projects do you feel this would solve for you?

If possible, screenshots / design images would make even better.

Also check out this:

http://www.noesisengine.com/webgl/Samples.Buttons.html

@jassmith It would have been great if the whole idea is presented as images. Kudos to the effort of putting the specifications up. My questions might be not correct.

My queries are

  • Tablet Support, Responsiveness of app adapting to different layout is not addressed.
  • Will the migration from the current model to the new model be challenging? From app developer perspective and Xamarin Forms contributors perspective.
  • I agree most of the app needs single UI (cause the amount of custom renderers we have to write sometime to achieve same UI concepts) without respecting platform specifics, will the new direction remove all the existing features, like will we still develop Xamarin.Forms apps with platform specific UI, or will everyone be forced to new Standards.
  • Will renderer concepts still exist inside MaterialShell
  • Can we actually say, in iOS, we want this to be rendered this way? Flutter has Cupertino Styles (apple UI) which works in Android, and Android UI which works in iOS. In What direction will Xamarin Forms move. Will developer have that kind of capablities which flutter offers now.

Will this also include something akin to the TextInputLayout to support floating labels/placeholders as well as error messages? If yes, then I think Binding should be extended to include 'ValidateOnDataErrors` similar to wpf.

See my implementation of this here
https://github.com/XamFormsExtended/Xfx.Controls/blob/develop/src/Xfx.Controls/XfxBinding.cs

Also, I wonder if MaterialShell should extend Shell so that one could create a HumanInterfaceShell for the iOS look and feel.

@ChaseFlorell that was going to be my comment as well. Material is great, but it's another thing if we want to write our own shells to suit particular UI needs.

@davidortinau , @jassmith ,

Thanks for putting together this spec and allowing us to provide feedback.

Is the problem that this proposal attempts to address well defined?

Yes. The navigation system is not completely developed in Xamarin Forms so there is an open ended issue of how to complete it, or circumvent it altogether.

Is it a problem you share?

Yes.

As you read this spec, what problems that you have faced on previous projects do you feel this would solve for you?

I'm going answer with this question by saying that I don't think it will solve problems. Our particular problems are that the current navigation system is too rigid, not that it is not rigid enough. The clearest example for us is the TabbedPage. There is no TabbedView view, so if we want tabs in our app, we must use TabbedPage. So, the whole screen must be taken up by the TabbedPage and we cannot use real estate for own buttons, or other controls that we might want to put on the screen. My recommendation would have been to move more functionality _out of_ Pages and down to Views rather than moving functionality in Pages up to yet again higher layer.

Things like FloatingMenu, and FlyoutBehavior scare me because they imply that navigation will be further hard coded in to the Xamarin.Forms system and further control will be taken away from the software developers. I can see some value in having a more standardized approach, but it will definitely come at a cost.

We have always worked in other XAML based technologies like Silverlight, WPF, and UWP. In those technologies, we have a much more open ended approach where we are able to define more of how the navigation works. Recently, we engaged a UI/UX consultant. He was unaware of XF's quirks. We just asked him to build us some screens based on the functionality of our software. Large swathes of what he recommended could not be implemented because of things like not having a TabbedView. I fear that instead of making navigation easier, what will happen is that this framework will actually make it harder to implement the designs that are given to us by UX/UI designers.

The other thing I would say is that this framework looks unprecedented in other XAML platforms, and I would say that the priority should be on providing standardization across the platforms rather than providing new frameworks that the other platforms won't be compatible with. We're currently building for three platforms now: Silverlight, Xamarin.Forms, and WPF. What we need is standardization across those platforms to create less deviation, not more.

@dylanberry ,

it's another thing if we want to write our own shells to suit particular UI needs.

Yes. This is my concern. Each app has its own particular use cases, and more rigidity is likely to make it harder - not easier to implement these.

There is also this concern: https://github.com/xamarin/Xamarin.Forms/issues/2452#issuecomment-380991817

I'll echo the above, as well as ask how gestures and pointers will function irt shape primitives?

A general comment is that for every line of code added to a system, there is 3+ chances of buggy code being added. There are already a lot of bugs in Xamarin Forms that need fixing. More code means the chances of bugs being added increase exponentially. There will be more bugs. I feel that the XF team should be working to reduce the size of the code base rather than increasing it. Decreasing the code base is the only way to decrease the likelihood that bugs will occur.

Why inventing a new thing again instead of fixing existing bugs and first make sure everything is rock solid?

For me, it's been touched on but navigation is the single biggest stumbling block in Xamarin Forms and has caused me the most heartache over the last three years.

The navigation is not consistent across all three platforms with MasterDetail pattern causing many issues with the hamburger forcing you to push pages modal, you then have to implement a custom navigation bar as you can't add back but the animation looks awful on Android (even in MD).

  • Ideally you should be able to opt-out and override the content of the navigation bar with your own ContentView in many cases. PlatformSpecifics was originally mooted as something which would have allowed positioning of toolbaritems (way back when I was speaking to Bryan) but it transpired to be something of limited use.

  • Ability to override framework stuff like page popped animations

A lot of what's proposed seems very very useful, As long as you can just use material shell in specific pages and it isn't app wide it code be really useful. It's certainly something we'd use because at current I keep saying "It's a limitation of Xamarin Forms" to our UX guy a lot (as I did in my previous role). Dare I say it, we should get the feedback from a UX perspective who have previously styled Forms apps. It's should be opt-in like XamlC.

Not sure about the name though, FlexShell would make more sense...but we now have Flexbox (even though we never asked for it...sorry David, couldn't help myself 😄)

Also, would this mean themes are kind of dead? never used them anyway.

@mackayn

It's certainly something we'd use because at current I keep saying "It's a limitation of Xamarin Forms" to our UX guy a lot (as I did in my previous role).

OK, but, wouldn't make more sense to fix or improve the current implementation instead of creating a completely new one, which will come with bugs and limitations too? It says right there that:

MaterialShell is an opinionated API at points"

Seriously, in how many different directions can Xamarin Forms go? The XF team is barely able to keep up fixing current XF implementation for at least Android and iOS, and now this? What about bug fixing, fixing XAML preview, what about performance?

There is\was a ticket opened by someone with a proposal to add simple but much useful support for cross platform solid and gradient brush, but @jassmith response was that it would be problematic. But now this ticket proposes the same thing.... How's that not problematic anymore? Go figure

@opcodewriter

Yes, I've been saying that for the last year, there's navigation weirdness that holds back the Prism team for example and they've never been able to get issues closed.

I'm just trying to offer constructive feedback for now though, Xamarin Forms is at a critical juncture in it's evolution, this API could address many of the pain-points if it's implemented in a flexible way and not an app wide approach.

@jassmith does this mean that XF will take the Flutter approach (using a rendering engine instead of native controls) for the Shell?

Folks, yesterday Jason and myself had a discussion on how to improve this spec and we will be doing a large update, we are splitting this into different issues.

I'd like to echo some of the above sentiments: please let's just improve on what we have, unless of course you have limitless resources, then go for it 😉

There are so many things still left out: fixing ListView (hard to believe this is still doesn't work properly), implement controls like CheckBox, RadioButton, implement brush support (SolidColorBrush, GradientBrush), ability to display a Popup based on a Page or ContentView, fixing bugs (see recent bug reported about transparent views), performance, tooling, and so much more....

Why would you want to start a new thing?????

@TonyHenrique Yeah pictures would be great. I unfortunately am not an artist and do not own the rights to the images I am using for my own reference. I am hoping some design team member will have time to help me produce proper images for the spec.

@muhaym

  • Tablet support. It is intended to make sure the layout is adaptive to tablets. This is not going to cover cases for layouting inside your content pages of course, that would be a different feature. Largely I would handle that with the new VSM.
  • Mostly just putting your ContentPages in the right place and adapting to the new navigation concepts. I wont say it will always be trivial but it shouldn't be debilitating either.
  • Absolutely will not remove any features. In fact I am working on updating the spec to include a Shell base class that misses some of the features of MaterialShell but is otherwise a platform specific UI version of Shell.
  • Yes. Adding a Drawing just changes which renderer you get to something that known how to handle a drawing.
  • Yes. You can swap out which renderer gets used at any level of the hierarchy. The renderers are just changed by templates being set with special keys in resource dictionaries. You can change these templates to whatever you want or disable them by setting null to them.

@ChaseFlorell no, but Im open to suggestions if you want to attach an amendment to the spec. As for the Shell vs MaterialShell thing, I addressed that above. Step 1 was making sure MaterialShell made sense then breaking it out to a base class is step 2.

@dylanberry the base class wont really make that much easier. Its not as simple as changing DrawingTemplates. I intend to implement the MaterialShell aspect of this in platform specific code for optimal performance.

@RichiCoder1 gestures will be coming in here but the gist is the views with subregion gestures are coming as part of the CommandableSpan API and it will be expanded to support drawings with gestures as well. However in general it would be advised NOT to use gestures and let the native backends handle input. This is unrelated to the MaterialShell spec at this point now and belongs on the Drawing spec where I am happy to go into more detail. The long and short is the reason DrawingTemplate is a thing is we may include a SliderDrawingTemplate which has multiple Drawings that the renderer knows how to compose a slider out of and allows the input handling to continue to be handled in the native backend. This does not mean you would be forced to do this, it would simply be an optional thing to make the renderer fast as possible.

@mackayn a Transitions/Segue API is coming and should land in here soon. I am still working out some of my initial proposal naming. It will certainly be something that comes in phases with only Page Transistions being in phase 1. That will let you override framework animations however. As for opt-in. The Shell must be the root of your application and cannot nest anything but TemplatedPage's. That said the internal control theming is 100% in your control. Its little more than a magic switch to turn on/off the new templates and you can control that switch the same way we will. This lets you opt in and out of the theming at the page, the layout, or even the control level.

@encrypt0r not exactly. Think of it as a hybrid. It will allow for rendering but under teh hood its all platform specific controls just being themed with drawing code. However there is an escape hatch to Skia that could be easily added (though I doubt it makes it anywhere near a v1).

@opcodewriter ListView2 (obviously it wont actually be named that) is on the roadmap this year at long last. Why a new ListView? Well the original API leads to a nearly limitless number of bugs and issues that we can't really effectively fix without totally breaking backwards compatibility. Things like Cell/ViewCell and ItemsView and the TemplatedItemsList while they worked well for what they were meant for a 1.0, are nowhere near capable of what they need to be for the modern usage of the API.

Unfortunately I cannot think of any way to resolve this within the ListView type itself, and I don't think the community has been able to either unfortunately. The best option right now is to keep ListView as it is, and then make something far sleeker with less overhead, less bookkeeping, less odd types that don't need to exist and trust the target frameworks to do what they do best.

Simply removing the old recycling strategy, which would be a huge backcompat breaking change we can't do, would remove a sizeable portion of the Xamarin.Forms codebase. ListView2 will bring you much closer to the metal by removing these items which were intended to be guard rails (or in the case of Cell, the unholy merger of 2 different internal projects) and are now just hurting everyone.

The old caching strategy impacts EVERY renderer in existence today. Its the reason why every renderer supports having its Element changed. If that went away by my best estimate about 10% of all code in the project goes away. It's really the biggest cancer of the project.

@davidortinau you get your own comment just because yours has so much lovely formatting!

If I use this approach to describe my application at the top level, I get:

  • an app themed to look the same on every platform
  • material design (in this case) patterns on by default
  • the latest navigation patterns enabled with configuration
  • I don't have to labor to customize Entry or Button to look the same on iOS and Android and UWP?

Is that accurate? Other benefits I should highlight?

Yes that is correct. There are lots of other benefits you can highlight but they should become obvious once you start messing with it. Like you can do bottom sheets, have a FAB, navigate using URLs (update still coming) and much much more.

Instead of App I have MaterialShell. I need to learn/adopt a new top level application paradigm to benefit from this?

Wrong. Your apps MainPage is the MaterialShell. Application is still your app root.

Once I'm into my app, I'm back in ContentPage land, correct? But all my Buttons and Entrys are material-fied and pretty.

With the exception to where you were wrong above, yes this is correct.

Can I still OnPlatform and the like to diverge the look (or behavior) to be different on another platform?

Yes.

What's my migration path look like from an existing app to using this "shell"?

Look at the Google Play Store repro case, imagine putting all your apps current pages in there. This only replaces those areas in your app where you are directly using Nav/Tab/MD pages. It doesn't have any impact on your ContentPages.

I introduce the new MaterialShell, describe how I want my app to be structure and look, and just run it to see the new goodness?

Bingo

What are my options if I like the way the Flyout or the menu items look, but I need to tweak them to match my designers comps?

You fully control the header, how the header collapses and hides. You fully control the look/feel of each of the "Cells" (they wont be cells) in the flyout. You fully control the header for each group in there as well. In effect you control the "look" of everything, however we still need to add a couple additional places for you to place extra content.

At what point am I saying "Ugh, I should've rolled this all myself" and moving what I have to a standard Xamarin.Forms app structure?

If the Google Play Store physical layout flyout looks completely different from what you want. Not marginally different, completely different.

If I have to totally abandon the MaterialShell, do I lose all that styling goodness and I'm back where I started (like today) with an Entry looking quite different between iOS and Android and UWP? I would like to not.

No MaterialShell is just setting some default resources so its children get them. You will be able to do that yourself. You might have to do it anyway, we haven't actually committed to making MaterialShell do that by default. If we do make it opt-in instead of opt-out, it will be a single API call for any subtree.

There's a tipping point I'm anticipating. After I've used this approach to get going quickly, I will hit some limitation and need to explore my options. What are they and at what point am I better off not using MaterialShell?

The intention is you are NEVER better off going non-Shell. You might not want Material but you should always want Shell (again the Shell base class is coming). Why? The look/feel of shell will be much more configurable, the navigation story will be much more unified, there should be nothing sane you can do with the other pages that you can't do with Shell.

Better, the intention is to make sure the Shell renderers are actually easily configured and sane. No magic hidden classes, not custom native view subclasses that we take hard deps on. As much as is possible every component of the renderers will be composed and swappable. That way if it doesn't work how you want it to, you can actually fix it...

Why didn't we do that at first? It wasn't a design goal in the early days and then we just ended up married to that... This is big enough and new enough that we dont have to carry that mistake with us.

@opcodewriter

Seriously, in how many different directions can Xamarin Forms go? The XF team is barely able to keep up fixing current XF implementation for at least Android and iOS, and now this?

What about bug fixing, fixing XAML preview, what about performance?

^^ This

@migueldeicaza

Folks, yesterday Jason and myself had a discussion on how to improve this spec and we will be doing a large update, we are splitting this into different issues.

Miguel, this is clearly going to be a big job. I can't speak on behalf of all developers, but I can tell you that my team wants three things: stability, performance and flexibility. We want bugs fixed. We want our app to run smoothly, and we want to be able to implement the designs that our UI/UX designers give us without turning around and saying "Sorry, that's just not possible in our platform". This spec seems to run counter to that goal. This is going to require more resources being thrown at the job which means that your resources are not freed up to work on stability, performance and flexibility.

Would this be the new default behavior/way to develop in xamarin forms? Or would we still have an option to build our apps with each platform specific look and feel?

@DanielCauser while I suspect in the long run this may become the "default" way, this will in no way replace the current way. It will simply be a more integrated and modern way which will provide a lot more of the shell people are currently building by hand by default. On top of that since we will be providing the shell as a single control we can optimize a lot about how its drawn and laid out. No longer will you have 3 drawing passes just for your shell.

I'm cautiously in favour of this idea, provided that the improvements it proposes are worked out by means of improvements in the underlying Xamarin Forms code. If this adds more complexity on top of Forms I would not use it.
For my money though I would much prefer to have developer resources directed towards making Forms more flexible, faster and finished than it is currently. If that happened, I could make all the proposed new features here for myself. DIY in this case is almost certain to fit me and my clients better than a generic toolkit provided by Xamarin, however good it might be. With a couple of notable exceptions this proposal doesn't solve problems I'm facing at the moment.

@jassmith

  1. There are more than 500 open issues.
  2. Xamarin Forms is 3 years old and there are still bugs in basic controls and functionality, important features are still lacking and performance has not been fully nailed down yet (I know some improvements were made, but performance on Android is noticeable subpar).
  3. The Xamarin Forms dev team is still undersized.

Why do you want to start working on this whole new feature now? Doesn't make more sense to focus on the above first?

About your comment above related to ListView: I applaud any kind of bold take on it, including completely redesign\replace it. It's not like everything is so great in Xamarin Forms things should not be touched\changed.

@opcodewriter

1) Yup there are. I agree its a problem and will continue to be the priority work item that I personally push for.

2) Performance on Android is part of the driving reason for this. This gives the framework more heads up time for page transitions so we can hide things like JIT time. We can proactively load and retain pages far more intelligently. What the X.F. team can't fix is overall JIT time. If you run your app in Android with AOT enabled and its much faster, there is nothing I can do to help you.

3) No arguments here.

Why do you want to start working on this whole new feature now? Doesn't make more sense to focus on the above first?

This work isn't scheduled, we are just discussing a spec here. My management will schedule it when they feel its appropriate with my advise.

About your comment above related to ListView: I applaud any kind of bold take on it, including completely redesign\replace it. It's not like everything is so great in Xamarin Forms things should not be touched\changed.

ListView truly is the bug bear of Xamarin.Forms. Of those 500 issues, 220 of which are marked as bugs (there are lots of housekeeping or enhancement issues too), north of 25% are just to do with ListView. For comparison thats about the same percentage that have to do with the entire UWP platform. Worse a fair number of the crashers in Android that are basically described as renderer gets used after dispose are also ListView bugs however they are unlikely to show up in my search since ListView will show up nowhere in the search query.

@jassmith beside fixing existing issues (beside ListView, there are other things which still don't always work right), there are also important features which were left out (random order):
- True popup support (basic and common feature still missing)
- Cancel page navigation when navigating back (long outstanding issue)
- Basic controls missing(no CheckBox, RadioButton, and more)
- Cross platform drawing (Canvas control or some other way)
- Support for cross platform drawing of solid\gradient brushes (SolidColorBrush, GradientBrush)

I wish more work was done in the direction of making the framework truly richer, and not add stuff like CSS style or Flexbox (which came with their own issues).

@opcodewriter

True popup support (basic and common feature still missing)

Fair, it never seems to get prioritized high enough to become real. This actually got pretty far along at one point.

Cancel page navigation when navigating back (long outstanding issue)

This is actually something MaterialShell is intended to address. There are pretty solid reasons this can't be done in NavigationPage.

Basic controls missing(no CheckBox, RadioButton, and more)

Some of these are part of the F100 initiative going on now.

Cross platform drawing (Canvas control or some other way)

That would be the sister API to this as speced in #2452

Support for cross platform drawing of solid\gradient brushes (SolidColorBrush, GradientBrush)

Same answer as above.

@jassmith

Fair, it never seems to get prioritized high enough to become real. This actually got pretty far along at one point.

OK, looking forward for prioritizing it by end of 2018 :)

This is actually something MaterialShell is intended to address. There are pretty solid reasons this can't be done in NavigationPage.

Could you please give more detail why this can't be done in current implementation?

Some of these are part of the F100 initiative going on now.

I see. Fingers crossed..

Could you please give more detail why this can't be done in current implementation?

I wont go into this more here because we are getting massively off track but the gist is as follows:

  • You cant cancel the back swipe gesture in iOS reactively. Since this is the primary method people use to navigate back with the larger phones this becomes a glaring omission.
  • While it is technically possible to override this behavior in iOS, it requires getting fairly deep into the internals of the UINavigationController in a way that we can't be sure will actually be supported or work when a new version of iOS comes out. In short Apple doesn't really seem to much enjoy people doing this.

There are some other minor concerns in there too regarding how it impacts styling. Thats the long story short however. If you still wish to discuss this particular feature I suggest opening a new issue :)

@jassmith
I thought just handling gestureRecognizerShouldBegin and call something like OnBackButtonPressed should be enough.

Overall I really like a lot of what I am reading, however this does not feel like something that should be done in the core Xamarin Forms nuget/repo.

This is an opinionated approach that should be built on top of Xamarin Forms, not built into it. I see this as a separate library that enables developers to take a different approach. The required parts of Xamarin Forms that need to be exposed should be, and this should be built on top of those bits.

Just like when developers make the decision to go with Xamarin Classic/Native or Xamarin Forms, I can see a similar decision to go with Xamarin Forms or Xamarin Forms with a Shell.

Xamarin Forms should focus on creating the best cross platform UI framework without trying to conform platforms to look like one another. Today Xamarin Forms does a great job of making sure platform feel is respected.

I could see a base Shell being in the Xamarin Forms repo and some code around handling Shells, but Material Shell seems too tightly coupled to a specific design language and navigation pattern for me to think it should be in the Xamarin Forms repo.

@MisterJimson
Thank you for your feedback. The exact placement of the public API surface area is not yet decided. There are pros and cons of both approaches.

The spec will be updated (hopefully very shortly) to have both a Shell and a MaterialShell class. The MaterialShell class would be the part we consider moving out of core. Shell would be what you have described.

Updated with Shell breakout and navigation spec update

I would really like it if existing XF implementation is made...stronger and better to enable something like this to exist as an addon, not as part of BCL. So having strong underlying platform that is correct and stable will benefit existing apps and any new layers like this one.

Looking forward to the evolution of this thing.

@jassmith @brianlagunas

Just a few observations.

  • BackButtonBehavior, surely there should be a visibility property in case you don't want it at all?
  • The materialshell navigation scheme is like Prism, will it work with these existing frameworks? (Prism, FreshMVVM, MVVMCross)
  • Can you override completely the layout in the navigation bar? as it stands Forms is extremely limited in this regard and you end up with clunky looking navigation bars forcing you down the customrenderer route, safe in the knowledge that a new version of Forms will most likely break your custom code.
  • MasterDetail isn't touched on much, will you be able to customise the flyout menu?
  • What control will we have over the hamburger?

I just want to ensure existing pain points and limitations are addressed as well as new having new capabilities.

Sounds great.

I'm very new to XF but the framework does have a bit of a reputation for being somewhat fragile, though certainly this is improving rapidly thanks to your efforts.

So for what it's worth, this is my opinion :-)

It's great that Xamarin getting a lot of love at the moment but I agree with @opcodewriter, both the tooling and the framework could do with some technical debt paying back.

I also like the thoughts from @MisterJimson that this should be a different layer - but you must be honest with yourselves about your capacity and how many frameworks you can support. We're all prone to coding exciting new shiny things, and avoiding the difficult decisions, but we rely on you to develop a solid foundation for our code.

I have enough problems getting my code working without worrying about someone else's :-)

XF is in a good place at the moment, it has the potential to become a really solid toolset.

Thanks for all your hard work on this, it does show.

@mackayn

BackButtonBehavior, surely there should be a visibility property in case you don't want it at all?

Set the command with CanExecute returning false. I opted to not add a secondary method for the moment.

The materialshell navigation scheme is like Prism, will it work with these existing frameworks? (Prism, FreshMVVM, MVVMCross)

I sure hope so! I can't be sure but I was thinking of them and all their troubles. Thats why all navigation happens through a single event for example.

Can you override completely the layout in the navigation bar? as it stands Forms is extremely limited in this regard and you end up with clunky looking navigation bars forcing you down the customrenderer route, safe in the knowledge that a new version of Forms will most likely break your custom code.

This part is harder. I would like to allow as much extensibility here as possible but I am really open to suggestions on how to improve this in a sane and reasonable manner.

MasterDetail isn't touched on much, will you be able to customise the flyout menu?

You can set the header to any arbitrary view, you control the template used for group headers and items, and you can add menu items. You control some aspects of the layout but not 100%. Again it would be good to get some thoughts on what else you think you need. I clearly see a need for a footer with a footer behavior property.

What control will we have over the hamburger?

BackButtonBehavior also overrides the hamburger. Perhaps it should be renamed. Again I am open to suggestions here. Originally I called it LeftBarButton, but in RTL situations its not on the left...

@stevehurcombe technical payback is continuing and ongoing. This will be run in parallel by a far smaller contingent of the team. Unfortunately the reality is a lot of this spec is about technical payback in a weird way. Xamarin.Forms incurred a huge amount of API debt with its 1.0 release, and has been carrying that debt ever since. Certain things in X.F. are very difficult to make work right, or even impossible to make work right, simply due to the way the API expresses them.

Tight interactions between tabbar and navbar is one such area, making sure navigating between tabs or items in the MDP is glitch free is another area. There are lots of areas where little hiccups will occur because each element is not able to take a holistic view of the shell of your app.

As for the tooling, there is an entirely separate team dedicated to this and they are making huge strides. The internal tooling has improved massively in the past 6 months and I really look forward to you getting to try that out!

@mackayn

The materialshell navigation scheme is like Prism, will it work with these existing frameworks? (Prism, FreshMVVM, MVVMCross)

Fear not, @jassmith brought this to my attention before the community realized the issue was here... so I can say with some confidence, it's an issue he certainly cares about as much as we do. You can be sure that it will be something that we look to support. Something of this magnitude will certainly require a lot of cross team dialogs to ensure that it meets the needs of the Forms developer at large, as well as meeting the needs of MVVM frameworks like Prism.

@dansiegel

Good to know both teams are in dialog, that'll all I needed to know 👍

@jassmith It's obvious by now the way some of things are running or were architectured in XF is not the best. So instead of putting lipstick on the pig (not wanting to be rude here), why not either recreate a new framework from scratch or massively refactor the existing one. I know, it sounds very scary, but I'm pretty sure the large majority of Xamarin Forms developers would not mind, all of us would be excited to refactor our apps or whatever just so we have apps which run much better.
I've seen PR rejected with good refactoring because "we do not want this kind of changes". I am not sure who made that rule, but he should take a deep breath, relax and maybe reconsider the "rule".
What is the best: Keep having frustrated devs using a framework which can't keep it up or having frustrated devs which need to do some refactoring work? Just my 2 cents...

@opcodewriter you and I agree but this is offtopic for this spec.

Just read the new material around navigation and I really like it. Love having a sort hand for binding navigation commands, and orienting navigation around URLs (like and I assume influenced by Prism) is smart.

Ironically the URI navigation scheme was something we wanted to do way back in the day and started push Prism to implement because we couldn't reasonably get it into the framework. Not to take any of their credit, they deserve 100% of that :)

The exact semantics of the shorthand are still up for grabs.

I think it will likely end up more like:

<Button Command="{segue:Uri}" CommandParameter="app://Foo/Bar/Baz" />

or

<Button Command="{segue:Push}" CommandParameter="{DataTemplate local:MyPage}" />

So the extensions can be more precise about what parameters they take. The namespace is used mostly to keep things easy to discover with intellisense.

@jassmith I really like that this segue stuff. Can I ask how you intend to support push modal?

I don't have all the details, but I could envision url nav just like prism, wrapped up in markup extensions.

<!-- push -->
<Button Command="{segue:Uri}" CommandParameter="path/to/page" />

<!-- push modal -->
<Button Command="{segue:Uri Modal='true'}" CommandParameter="path/to/page" />

<!-- reset stack -->
<Button Command="{segue:Uri}" CommandParameter="app://root/path/to/page" />

First thing to note is that URI navigation will only work with Shell. It's the only place we can consistently make sense of the stack without having weird edge cases and we can design the navigation interactions to support the concept.

For now we are only supporting full URIs. Partials are a lot harder to deal with because they are contextual.

Your 3 examples then would be, assuming the current location is: app://Shell/Apps/Games/Details

In particular this means you are in an Shell, whose current ShellItem has the Apps Route, whose current ShellTabItem has the Games route, who has a ContentPage pushed onto its stack which has the Route Details.

<!-- push -->
<Button Command="{segue:Uri}" CommandParameter="app://Shell/Apps/Games/Details/page" />

<!-- push modal -->
<Button Command="{segue:Uri}" CommandParameter="app://page" />

<!-- reset stack -->
<Button Command="{segue:Uri}" CommandParameter="app://Shell/Apps/Games" />

In a shell uri the first location is always a Shell. If it is not it is assumed to be a modal push. Next is the ShellTab, then the ShellTabItem. After that follows the navigation stack of the ShellTabItem. I have no intention of backporting URI nav to all possible page controls at the moment. This gets REALLY hairy with people who use MasterDetailPage's...

With Route registration and Route properties there is no need for type based routing. I am going to remove it form the spec.

@jassmith giving more thought to this navigation stuff, and I have some questions

  1. how can you handle CanExecute
  2. how can you give the user control over (read prevent) multiple taps?
  3. how do you handle relative navigation? IE you're 3 pages deep and need to go to the forth, but the stack is fully dynamic?
  4. prism has this fantastic notion of NavigationParameters whereby we can pass not only basic values via the querystring /Navigation/MyPage/MyPageDetails?id=33, but also complex objects new NavigationParameters {{nameof(MyObject), MyObject}}. Do you plan to support something similar?

@ChaseFlorell

1) With segues? You can't currently. Definitely needs to be thought about more. There is a way to make a segue command but it... sucks. That would let you handle it but at that point its REALLY not worth it.

2) A Segue will disable itself until the push is completed. Further attempts to activate the command no-op until the previous navigation task completes.

3) You can use a traditional navigation like push/pop with segues. These are relative actions.

4) [QueryParameterAttribute] may or may not already exist, I can neither confirm nor deny. ;)

It is unlikely we will add complex objects support. The idea is you use converters to take your simple values and turn them into complex objects.

From past experience building URI-based app navigation (back in the CAB-Composite UI Application Block for p&p), I'd strongly suggest you do not use the System.Uri type and instead just make everything look like a URI, but not use the URI implementation itself. @pprovost can testify to the life long scars that work must have left in him. I remember hitting countless issues as we faced internet URI restrictions and errors (i.e. on host names) that we couldn't care less for in-app stuff.

Part of the damage already done, I suppose.

Actually the System.Uri is the best choice when supporting a URI based navigation scheme. While CAB did use URI navigation, it also did as you say and made it "look like" a URI by allowing you to use strings instead of the System.Uri object. Host names were never required.

What you are asking for is a very loose string based API which can accept any string syntax you put in it, which is not something that is going to produce predictable results. There must be rules in place for a URI/string based navigation scheme to work.

An arbitrary URI won't work in XF either. The list of invalid characters in a URL but which are valid in a file system is not precisely small. Those are all cases where a string would have worked, and a URI will not and will need either escaping or having the user figure out why things aren't working (or fail?) and rename stuff to be "URI safe".

You can make up your own abstraction if you want more restrictive (or better semantics/parsing/validation?), but IMHO, System.Uri brings a lot of internet baggage that is not for free. This is similar to how Mono/MonoDevelop created its own FilePath to represent paths, which are typically just strings.

At least, it seems all URIs are considered relative, which simplifies things. In CAB we used absolute uris with scheme and hostname parts too, which was problematic.

I'd much rather prefer something like a ResoucePath, say, than a Uri. But this late in the game, I'm pretty sure it's done deal anyway.

Im not sure what you think filesystem paths have to do with anything...

How would you use a URI to confuse the sysem? Its going to ignore the scheme and the hostname and start looking for routes (which are limited to [a-z] only). If whatever strange characters you put in cant be found it just stops. And query string you put in needs to be valid C# identifiers or it simply wont be matched. Escaped data in the query string data will be unescaped.

@kzu URI's work just fine in XF, and is a better fit for XF than a file system schema would be. In fact a URI is expected when launching your app from a website. You should check out how powerful URI based navigation can be by looking at the Prism implementation. Out of all the apps out there built with Prism using a URI based navigation scheme, never has an issue be submitted related to invalid characters. I am confident your concerns about a URI based schema for the XF platform will not be an issue.

Makes sense. Thanks for the background info on Prism @brianlagunas! Now I should carefully read the spec and provide some actually useful feedback ;)

Very good initiative, but I hope extensibility and customization is taken into account by creating the proper virtual methods or other ways to do our "special" thing for our customers.

For example will it be possible / how to:

  1. Tabs extensibility for example showing a badge with an icon. Or showing a popup drawer above one such as a "more" or "*" button.
  2. Custom snackbar (for example with "Undo" button for an action you just did with custom background /foreground colors)
  3. Fragment pushing in Android using different animations than the default programmed in the Shell, like no animation to give the fastest possible navigation.

On a technical note: will the shell recycle pages so that once a navigate twice to a page, the native elements will be re-used with a different vm under it?

Hi @rogihee

I welcome your feedback on the implementation. I think it is crazy extensible: https://github.com/xamarin/Xamarin.Forms/blob/9558f2837280e02b41848d3a3c3213d49a664751/Xamarin.Forms.Platform.iOS/Renderers/ShellRenderer.cs

Android is still under heavy development right now, however it uses an identical approach.

@rogihee as for recycling of pages, I am trying to figure out a sane method of making that viable. Generally speaking it doesn't currently since it would need to be explicitly opt in.

Looks good these "Create*" options. Good to see the swift progress on this!

I wonder if there are any performance implications with re-using elements. Personally, I would prioritize the speed and "fluid" feel of an app over higher Mem/CPU usage (although there is a correlation somewhere in the end of course). And prioritize iOS / Android over anything other :-).

Shell very much is focused on perception of fluidity. Its not in place yet everywhere but its coming together.

I really need to get some early users in place that try to do crazy things with shell to make sure it can handle the load it is designed for.

@jassmith mig just mentioned shell for 3 minutes in Build.....

Im not his daddy

+1

Updated API to match current state of the world, still need to update the samples.

Added some updated samples, still need to do a lot of work fixing other samples and updating descriptions of routes when using shorthand syntax (as you get shorthand routes!)

Gosh, I feel so late to the party. Great writeup and discussion. I skimmed through it all (sorry at the airport) and have a suggestion of my own. Sorry if this was mentioned somewhere else.

@jassmith @migueldeicaza Can you please please add behavior to the navigation bar so that it can be scrolled off when the ListView is scrolling and shown when it’s scrolled in the opposite direction. Almost any professional app out there does this to show more real estate. This would be especially useful on small devices.

Another one is why don’t you rename the XAML tags so they are simpler to grasp? Maybe use Tab instead of ShellSection? There’s a lot of ShellX tags now.

For iOS, I believe there is a property to switch on/off to enable scroll mode on the navigation bar. For Android, you need to start using the new layouts (CoordinatorLayout, AppBarLayout, etc.). XF’s Android implementation is quite outdated in this regard as it is still using a RelativeLayout as the main container. I think there is an Enhancement ticket somewhere about this specific issue. I’d love to see Shell support different scroll modes.

Also, we often have to implement custom behavior to show errors/other types of popups on the page. Shell should support this functionality out of the box so we don’t need to resort to 3rd party plugins or create complex UI hierarchy.

@adrianknight89

Can you please please add behavior to the navigation bar so that it can be scrolled off when the ListView is scrolling and shown when it’s scrolled in the opposite direction. Almost any professional app out there does this to show more real estate. This would be especially useful on small devices.

Thats something I am really trying to figure out the right way to do. Unfortunately not all platforms support this feature so it will probably end up being a platform specific deal. Android at the very least was constructed ground up to support this, I turn it on occasionally to make sure it still works.

Another one is why don’t you rename the XAML tags so they are simpler to grasp? Maybe use Tab instead of ShellSection? There’s a lot of ShellX tags now.

The naming here is REALLY hard. ShellTab is a bit confusing for top vs. bottom. I instead opted for more generic hierarchal names, however I have to admit Im not happy with naming. Suggestions are 100% welcome... not wholly looking forward to refactoring their names AGAIN but what can ya do...

For iOS, I believe there is a property to switch on/off to enable scroll mode on the navigation bar. For Android, you need to start using the new layouts (CoordinatorLayout, AppBarLayout, etc.). XF’s Android implementation is quite outdated in this regard as it is still using a RelativeLayout as the main container. I think there is an Enhancement ticket somewhere about this specific issue. I’d love to see Shell support different scroll modes.

Shell uses CoordinatorLayout + AppBarLayout and basically "disables" the scroll away support for the moment, it does work however. iOS scroll off is also easy to implement. Unfortunately UWP's NavigationView has no support for this feature.

Also, we often have to implement custom behavior to show errors/other types of popups on the page. Shell should support this functionality out of the box so we don’t need to resort to 3rd party plugins or create complex UI hierarchy.

Examples, I need examples :)

@jassmith

I’m using James Montemagno’s connectivity plugin to listen for changes in data connection state. When Internet connection drops, it’s good practice to display a notification that slides/fades in and out or stays stationary until the Internet comes back online.

On Instagram, this notification is placed right below the navigation bar. On Tumblr, it’s right above the bottom navigation bar. On YouTube, strangely it’s below the bottom navigation bar. Maybe something like this can be part of Shell?

The proposed Popup control is, as far as I know, overlaying the existing window though it can be light dismissable. The notification I just mentioned and potentially other types of notifications don’t need to overlay their parent window (i.e. parent visual tree is still responsive to gestures), so I’m not sure if Popup is the right fit.

Shell can have a property for us to define how this View (call it Notification[View]) will look as well as its placement and entry/exit animation behavior. So essentially a cross-platform toast/snackbar implementation built-in to Shell, INavigation, or something else. This wouldn’t be forced to look native per platform but the same across all.

d1c014c0-fc7b-4788-9689-1948a7294426

bc91d3ca-b95f-4485-a917-db6ab47510c1

With regards to the arguments being made around stability, flexibility, etc., without getting rid of outdated architecture coming from 1.0, I don’t think it’s feasible to achieve those things. I’m very much in favor of ListView2.

@jassmith

  • Do you have an enhancement ticket for the new ListView yet?
  • When do you think v1.0 will be out? Any chance we could see it by EOY?

Also, I do have the same concern about the team being undersized. In fact, I’ve brought this up before in the past. I hope the team can grow much bigger in the future. 🙏 @davidortinau @migueldeicaza

@jassmith I've believed for a while now that if we had a Renderer for the App class we could do a lot that currently requires 3rd party hackery to achieve. For example, the RgPopups plugin grabs the main view of the app and injects rendered views into it to provide a whole-screen popup look. This is currently impossible to achieve with "pure" Xamarin Forms. However if App had a Renderer we could do this ourselves.

I'm all for adding these kinds of toast notifications to Shell, just trying to figure out how it should be done.

Can you please make so that you can put pages arbitrarily wherever you want inside an application? This is especially important on tablets/desktop/laptops (larger screen devices), where you want multiple pages on screen at the same time, and don't necessarily want to organize it using a split view (master detail page). Example, see Google Maps:

image

Notice how the content is "floating" on top of the map (no split view). If you want to use things like tabs, or navigation inside the floating area, then you can't accomplish this sort of thing with Xamarin Forms, out of the box, because of the extremely limited hierarchy with pages (can't nest a page inside a view). We actually developed our own custom view that provides capabilities similar to NavigationPage but is a view, just so we could accomplish this sort of layout, but it was a lot of work / hard to do.

It should be possible to put content (including pages) anywhere you want inside an application.

Can you please make so that you can put pages arbitrarily wherever you want inside an application?

I'm a bit curious @jsiemens since this view would likely not look right on a Phone, but look great on Desktop and Tablet. Can you expand on how you might expect that to work. Ultimately I'd be tempted to say you're bringing the Region concept into Forms from Wpf. My knee-jerk reaction is that while I love the concept, we risk making an already complex Navigation API require a PhD or at least a genius level IQ which wouldn't be the greatest thing for user adoption.

@dansiegel At least personally, I'd probably use VSM or some equivalent to move and compact the scroll view on the bottom when below a certain viewport threshold (like GMaps does currently). Would be curiou to see how navigation and state management would work for that though.

Navigation: I'm sure that's not an insurmountable problem if you started from the perspective of the user journey and then looked at how the user would expect it to work. The navigation would need to be responsive to the full screen nature of a phone vs a smaller view on a larger screen for example.

The user would 'see' the tablet and smaller view as a single navigation milestone. On a small screen there could be two milestones. The navigation would, somehow, have to be responsive.

As developers we surely have to handle that responsive nature as it is a contextual thing. We cannot rely on the framework to handle that for us, but the framework needs to support it.

@jsiemens @dansiegel The way I handle this currently is using ControlTemplates. I build my "page"-type content as ContentViews and host them in a ContentPage (inside a NavigationPage) that's appropriate to the platform. Using ControlTemplates means I can have multiple bound ContentViews (usually in a Grid so I can overlay stuff) that get switched on/off based on bindable properties in the ControlTemplate itself (you can also use DynamicResources). The end result works a little bit like CSS panels on a web site, where all the content is in the page but not all of it is visible all the time. ControlTemplates are magical for this and I would want their capabilities to be preserved in Shell.

@dansiegel I would simply code it to load different a different shell depending on if the app was running on a phone vs a tablet/laptop/desktop.

@jsiemens that's fine, my comment is only meant to spur further conversation and critical thinking to further refine your idea. In some ways I'd almost say given your concept here, that every page could essentially be a MultiPage where a Page could be attached to a given control and treated more as just another View vs normal navigation.

@dansiegel Yeah, I think that's what I'm after is to be able to just add a page to anywhere within the application. It's weird that Xamarin Forms imposes this limitation when the underlying platforms don't (eg. iOS is just a tree hierarchy of views - you can add NavigationController's view to literally anywhere within the application). Also, my comment was meant to indicate that it's not necessary for the Shell spec to cover this - I don't think that "responsive" layout needs to be a concern. I think so long as it's possible to build the layout, then we can take care of conditionally loading shells depending on form factor, and that's good enough.

I suppose it's not entirely on topic for this spec, but I mentioned it here because we're talking about how to construct complex layouts (eg. @MelbourneDeveloper 's 3rd priority - flexibility), and this is a certainly a layout that's top of mind for me and my team (we're building a mapping app where we want to be able to float content panels on top of the map, that could contain 'page-only' content like navigation pages and tabs).

I don't know how this would be solved using shell, but my initial reaction to shell is that it doesn't seem to do anything that I can't do already. I generally feel like the Xamarin Forms team keeps building features that let me do things that I already could do, but just in a different way (eg. CSS, Visual State Manager, and now the Drawing and Shell specs). So that doesn't bring much value to me. I'd rather have new features that allow me to do things that I previously couldn't (outside custom controls and/or renderers). If shell is the answer for accomplishing that because the syntax is more elegant, then I'm all for it, but ultimately I would like it to be more powerful and more expressive than current Page/View hierarchy for it really bring value.

Could you decouple from creating native view per xamarin view if all subviews within a layout can be rendered without using native widgets? Kind of a automatic hybrid flutter/xamarin approach where groups of XF views are rendered to a single surface and just blitted out onto one native view. Avoiding the Android view creation/layout c# -> java interop cost would be useful.

in progress!!

@jassmith after shell finished, will draw be valid together?

does shell going to support macos and wpf?

@juepiezhongren the initial targets are iOS and Android. Other platforms will be prioritized after that.

Drawing is not currently being developed. In its current spec, it would be valid with Shell. Just as today you can use SkiaSharp and Skia based controls within Xamarin.Forms.

We are working on other native strategies to support consistent design for material and other design styles.

@davidortinau Does the shell make RTL support better?

Better in what way? What are you missing from the RTL support today? We should address it everywhere.

To be honest, I haven't done XF development in a while, but most of the limitations are known: Take a look at #1222 and #2448

Maybe shell can help with these general limitations:

  • NavigationPage button location, toolbar item location, and transition animation is currently controlled by the device locale, not the FlowDirection setting.
  • Global app setting for FlowDirection

And some other platform-specific limitations

Most important feature of Xamarin.Forms. It should have been built like this in first place.

without drawing, xf still lacks quite a lot

@juepiezhongren

Just use Skiasharp

@mackayn i used it a lot
https://github.com/xamarin/Xamarin.Forms/issues/1789
universal looking is a must

adam went to flutter, it is really a sad sign for xf, where xamarin originally could rather easily achieve much better reputation

xamarin.native is much much more solid for xf, than any other cross-platform solutions, whatever react native or flutter. As dotnet lover, xf's current situation is always a little disappointing for me.

@juepiezhongren

This discussion is pointless, if it doesn't meet your needs use Flutter, it allows us to deliver apps across multiple platforms (iOS and Android only with Flutter etc), these changes will make a consistent look and feel more achievable.

simple small complaining, just so much. Still hooray for shell!

I'd agree it would be nicer to have Skia much more baked into the Forms api (like Telerik have done). I do agree.

I'm glad they are investing the effort into Shell & CollectionView though.

hi,please everyone say , how can i use shall flayout in right , for right to left language.

Hi,

I love the idea, but I have just some small inputs.
I guess I am a little late, but the naming is a little bit confusing, I think.

  1. Item, Section, and Content are all, really general names. It isn't right away clear in what relation those are. Is it Content => Section => Item or Section => Content => Item, or Item => Section => Content.
    So we might can specify a bit more what the different "things" are, by finding a more specific name.

  2. That leads me to the next input. We have a Shell as container for all inner items. So can't we just use straight forward names like "Item" instead of "ShellItem" inside. It looks for me a bit unnecessary to call all the "things" Shelltem, ShellSection etc. but ok. thats arguable.

Ouch

Will it still be released in 2018?

We have a preview release available NOW! Take a look at https://blog.xamarin.com/connect-2018-xamarin-announcements/ for some great samples.

Do we really need Android 9? That would seem to be a bit of a limitation.

It all sounds pretty good, but does appear to based purely around UI interaction.
I guess I'll find out when I try it, but my initial concern is how do I drive navigation from business logic or code e.g. messaging received form a Bluetooth connected device triggering a page change, whilst maintaining a decent separation of concerns?

@hassanrahimi

hi,please everyone say , how can i use shall flayout in right , for right to left language.

While RTL is supported, the flyout menu still appears on the left. This is a current limitation.

Is it possible to customize the bottom tabbar ui?

Is it possible to add a controls to the shell which is not reloaded when navigate inside the shell? For example a FAB..

@stfnilsson bottom tabbar UI is customizable via styles and then a custom renderer. We'll be providing examples in the future.

Adding controls that are global as you describe like a FAB are planned for MaterialShell. Can you provide additional scenarios that would benefit from this in addition to FAB?

First: I have used my own shell before, now I can pretty easy just replace my own with yours and it's much better. I really like it.

Probably are my cases way to custom and not related to shell but:

Case one:
If I want to create an app with a very custom menu, one menu button in each corner of the app, how do I add the buttons so it's part of the shell (like overlay or billboard). Don't want it to rerender each time I navigate.

Case two:
I want to use the shell but want to customize the bottom tabbar so the middle button is heigher(called center raised button). Should I use the renderer and customize Bottom Navigation View?

Do you think I should use the shell for special cases like this?

Of course I consider doing it on each platform but the menus should look the same on all platforms so want to share the code..

Here is my feedback. I do this test (Xamarin.Forms 4.0.0.8055-pre1):

   <Shell.FlyoutHeader>
        <local:FlyoutHeader />
    </Shell.FlyoutHeader>

    <ShellItem Title="Home" Icon="home.png">
        <ShellSection>
            <ShellContent>
                <local:MainPage />
            </ShellContent>
        </ShellSection>
    </ShellItem>

    <ShellItem Title="Notifications" Icon="notification.png">
        <ShellSection>
            <ShellContent Title="Recent">
                <local:NotificationPage />
            </ShellContent>
        </ShellSection>
    </ShellItem>

    <ShellItem Title="Test" Icon="icon.png">
        <ShellSection Title="Home" Icon="home.png">
            <ShellContent>
                <local:MainPage />
            </ShellContent>
        </ShellSection>

        <ShellSection Title="Notifications" Icon="notification.png">
            <ShellContent Title="Recent">
                <local:NotificationPage />
            </ShellContent>

            <ShellContent Title="Settings">
                <local:SettingsPage />
            </ShellContent>
        </ShellSection>
    </ShellItem>

All works when we tap the hamburger menu. However, if we go to Test menu and tap Home and Notifications back and forth and choose between Recent or Settings, the page will open respectively. But then, when we tap the hamburger menu again, the app crashes.

image

How can we use GroupHeaderTemplate to show a title for a group of ShellContent in a ShellItem ?

It's clear to many users that Xamarin Forms is not maintainable at its current size and complexity, so anything new should decrease complexity rather than increase it.

@jassmith The intention is you are NEVER better off going non-Shell. ... The intention is to make sure the Shell renderers are actually easily configured and sane.

If Shell gets completed, what in future can be depreciated, and when that is done is the overall complexity of Xamarin Forms reduced? Will all other Pages except ContentPage get depreciated?

The strategy should be to get as much out of the repo as possible. The stability and maintainability of the core repo is the most important thing.

Also if there a reason Shell isn't called ShellPage? Other Page classes have names ending in "Page".

The current advert for Shell (in https://blog.xamarin.com/xamarin-forms-4-0-preview/ ) is not promising.

  1. A simplified way to express the high level of your application architecture

This takes Xamarin beyond it's real purpose. Xamarin is not needed for application architecture. This should be about layout only.

  1. A hierarchy of common UI navigation patterns that suit your target mobile platforms

I hope "mobile" is a misprint here because Xamarin.Forms covers desktops too.

  1. A robust navigation service

Xamarin.Forms doesn't need navigation. If current navigation isn't working it can just be depreciated because there are many good approaches to navigation that don't require anything to be built in.

Hi @charlesroddie, thanks for the feedback.

It sounds like Shell may not be right for you at this time, and that's ok. You don't need to use Shell if it doesn't provide value to your apps. That said, the Shell spec is informed heavily by developer feedback, and serving our developer community is core to our purpose.

In Xamarin.Forms today you already describe your application architecture, the hierarchy of content, using TabbedPage, MasterDetailPage, with tabs and menu items, and different combinations. This is what I mean here by "architecture". Shell simplifies and replaces those patterns (if you choose to use Shell).

"Mobile" is not a misprint and it is used very deliberately. Shell is targeted at iOS and Android. If you are targeting desktop, you will not use Shell. I have heard interest from contributors about adding Shell support to the desktop backends, and those PRs would be well received. I believe Shell is very well positioned to take apps to any platform, and be flexible (resilient) to adapt to even radical UI pattern changes (who knows what future interfaces will adopt). For today the proving ground is iOS and Android.

As we have talked to developers about Shell, I was surprised to learn that the Shell navigation was at the top of the list of features they valued. The routing, deep linking, ability to interrupt navigation, instantly describe the back stack, pass data, and lazy loading of pages are very compelling attributes to developers that solve problems they experience today.

If you are targeting desktop, you will not use Shell... I believe Shell is very well positioned to take apps to any platform

I just don't want Xamarin to collapse under its own weight. Until Shell reaches all platforms you have a maintenance problem, since it is then an addition, not a replacement for other Pages. You also have a messaging problem for desktop developers, at a time when many are obviously looking to adopt a cross-platform framework.

Xamarin is showing a lot of feature creep, e.g. css. This could threaten the whole project and I hope some decision makers in the organization understand this.

I just don't want Xamarin to collapse under its own weight. Until Shell reaches all platforms you have a maintenance problem, since it is then an addition, not a replacement for other Pages. You also have a messaging problem for desktop developers, at a time when many are obviously looking to adopt a cross-platform framework.

Xamarin is showing a lot of feature creep, e.g. css. This could threaten the whole project and I hope some decision makers in the organization understand this.

I agree. If a feature isn't supported on desktop (UWP), then it's of no use to us. I also agree about CSS - it seems like a lot of added complexity, and maintenance overhead for a feature that doesn't let me do anything I couldn't already do before. What we need far more than anything else is just more controls - for all platforms, and more capabilities for existing controls. Shell still has the same limitations that the Page infrastructure has in that you need to adopt it completely or you can't use it at all, and it can only live at the root level of your application. Not only that, but now you have two ways of doing the same thing, and it's complicated and confusing. So if I want to just have a flyout menu without using shell, I can't do that. And it's extremely limited in the amount of controls that the shell items map to - tabs, navigation pages, and flyouts aren't enough for us. If Xamarin Forms could offer the breadth of controls that a framework like UWP has, exposed as a set of controls, just like in UWP, and without the useless bloat (eg. css), then I would be happy.

I think you guys raise some valid points, but as someone who maintains a UWP/iOS/Android app and was slightly disappointed when I learned Shell didn't support UWP, with only a "maybe" in the future. Then I realized I'm missing the point of Shell. It's a great easy way for someone to build an app for the two primary mobile platforms. As an enterprise developer...I need UWP, I waited until there was UWP support to even consider XF...but I suspect a lot of developers don't need it...I also need way more complex navigation, etc then Shell provides.

But I also remember spending a lot of time trying to get started with navigation and pages...which can take some time to figure out. But I'm also making a very complex line of business app, there are tons of simple apps that just don't need that level of complexity. XF needs to evolve to complete against things like Flutter, etc. It also needs to keep getting new developers to adopt it. And it seems to me usage of the platform will help secure the resources needed to maintain the platform.

I also have a couple future projects where I don't need UWP and I'm looking forward to using Shell on them because I think it will make it much faster for me to produce them.

I've only been using XF since around the 2.3 release and while there is certainly more work to done...the platform as it exists now has stabilized greatly...at least for me...so I'm not concerned with the additional maintenance and historically it seems to me the XF team is very conscious of maintenance burden...so I trust they have it under control.

Thanks for the great addition to the platform!

Adding new ways to do things will confuse new devs until the old ways get depreciated and the old docs removed.

Flutter is a lot simpler. No markup language, everything in code. Xamarin isn't going to compete by becoming more complex and buggy. It will compete by doing more than Flutter (more platforms), with the same focus.

It's getting to the point we need a Xamarin.Core, not including XAML or CSS or property bindings, not including Pages or Shells beyond the base classes, with a focus on performance and stability for this Core. If some devs want these features at the cost of accepting the current rate of bugs they can use Xamarin.Extensions where all those things would live.

Adding new ways to do things will confuse new devs until the old ways get depreciated and the old docs removed.

Flutter is a lot simpler. No markup language, everything in code. Xamarin isn't going to compete by becoming more complex and buggy. It will compete by doing more than Flutter (more platforms), with the same focus.

It's getting to the point we need a Xamarin.Core, not including XAML or CSS or property bindings, not including Pages or Shells beyond the base classes, with a focus on performance and stability for this Core. If some devs want these features at the cost of accepting the current rate of bugs they can use Xamarin.Extensions where all those things would live.

@charlesroddie Nothing they have done above are you forced to use XAML. XAML in Xamarin.Forms is optional - it always has been. I always do my Xamarin.Forms apps UI's using code only - every "tag" you see above is a class that can be instated and added to the relevant parent.
If coded UI's weren't possible with Xamarin.Forms I would not use it - full stop!

Re Flutter in general - its very nice, but the issue is its only iOS and Android - that doesn't work for me either as I need to target macOS, Windows 7/8.1, and Linux. Nothing beats Xamarin.Forms on this!

can I set custom view as a master page, it's very important thing to include, we will not prefer just MenuItem or pages

Xamarin Mac and uwp support?

How would you hook into the navigation process? I guess you are aware of that but if you take Prism for example, view models are created by a DI container and are automatically set as BindingContext for the requested page.

You could also implement INavigatedAware for a view model and handle specific use cases like loading data, enabling / disabling services, etc.

I wanted to add something similar so my first guess was the OnNavigating and OnNavigated Shell event but Current and Target do not expose a ShellItem so it's not possible to set the BindingContext by convention or trigger view model events?

Any suggestions for this?

EDIT: Tracked by #5166.

For the icons in this shell, is that possible to use "Icon Font" instead of a picture? It is difficult to change color during runtime for picture and It's also difficult to manage them for different resolutions on different platform. Can I suggest to make an icon class using Material Design font rendered with SkiaSharp library? The class is relatively easy and will make lots of icons ready to use on the shell.

@vincentwx I agree. Icon fonts are so much easier to use and are familiar too.

@vincentwx @stevehurcombe absolutely. I'm doing this in an app right now:

<ShellItem>
    <ShellContent Title="Upcoming" 
                      ContentTemplate="{DataTemplate pages:UpcomingPage}">
            <ShellContent.Icon>
                <FontImageSource Glyph="{x:Static local:IconFont.Rocket}" 
                                 FontFamily='{OnPlatform iOS="Font Awesome 5 Free", Android="fa-solid-900.ttf#Font Awesome 5 Free"}'
                                 Size="18"/>
            </ShellContent.Icon>
        </ShellContent>

        <ShellContent Title="Latest" 
                      ContentTemplate="{DataTemplate pages:LatestPage}">
            <ShellContent.Icon>
                <FontImageSource Glyph="{x:Static local:IconFont.Book}" 
                                 FontFamily='{OnPlatform iOS="Font Awesome 5 Free", Android="fa-solid-900.ttf#Font Awesome 5 Free"}'
                                 Size="18"/>
            </ShellContent.Icon>
        </ShellContent>

        <ShellContent Title="Company" 
                      ContentTemplate="{DataTemplate pages:CompanyPage}">
            <ShellContent.Icon>
                <FontImageSource Glyph="{x:Static local:IconFont.Building}" 
                                 FontFamily='{OnPlatform iOS="Font Awesome 5 Free", Android="fa-solid-900.ttf#Font Awesome 5 Free"}'
                                 Size="18"/>
            </ShellContent.Icon>
        </ShellContent>
    </ShellItem>

I used this to make a static class of all the glyphs: https://andreinitescu.github.io/IconFont2Code/

There is a bug with iOS color that needs to be fixed. #5071

Xamarin Mac and uwp support?

Not at this time @mdonogma. We are gathering interest/demand for supporting additional platforms, but at this time it's not on our roadmap.

@davidortinau Thanks for the code and link.

In Android 8.0, I cannot scroll webpage in WebView element that is hosted in Shell Content. But it works fine without Xamarin Shell.

Xamarin Form 4.0.0.135214-pre4

Is there an easy way to change the FontFamily of the bottom tabs and title view?

@varyamereon I did that yesterday. Extenend the Shell to be able to set FontFamily.
I will publish my extened Shell at GitHub soon but:

Create a custom Shell:

<Shell
    x:Class="X.Mobile.App.Features.AppShell.AppShell"

Then create a Shell custom renderer:

[assembly: ExportRenderer(typeof(AppShell), typeof(AppShellRenderer))]

namespace X.Mobile.App.iOS.Renderers
{
    [Preserve(AllMembers = true)]
    public class AppShellRenderer : ShellRenderer
    {
        protected override IShellItemRenderer CreateShellItemRenderer(ShellItem item)
        {
            return new CustomMenuRenderer(this)
            {
                ShellItem = item
            };
        }

Then:

 namespace X.Mobile.App.iOS.Renderers
 {
     [Preserve(AllMembers = true)]
     public class CustomMenuRenderer : ShellItemRenderer
     {
         private SKCanvasView _skiaSharpPaintView;
         public CustomMenuRenderer(IShellContext context) : base(context)
         {
         }

public override void ViewDidLoad()
{
}           
public override void ViewWillLayoutSubviews()
{
{

Then to set font family: _(don't do it to often)_

var txtAttributes = new UITextAttributes
            {
                Font = UIFont.FromName("MyriadPro-Semibold", 12.0F)
            };
            foreach (var uiTabBarItem in TabBar.Items)
            {
                uiTabBarItem.SetTitleTextAttributes(txtAttributes, UIControlState.Normal);
            }

Anyone who have extended the Shell with support for a popup from below (bottomsheet)?

I have moved much code from my own old Shell to the new one (composition of course), I really like it. I even use it for an app which will be released to prod i May :-) (I debug even the Xamarin code)

Is there support to bind a list to the Shell.MenuItems? Or should I use BindableLayout? Sometimes I require to load a list from the database and use these as menus. They have the same view, but load different data depending on the menu that is selected.

Is there any way to change the OffscreenPageLimit in Android when using shell? This is unfortunate very important for my app and is preventing me from moving forward with Shell.

Thanks!

A couple feature requests:

  1. At the shell level, set the FontFamily for all of the page titles.
    e.g.

  2. At the shell level, set the Title/Nav background image for all of the page titles/nav bars, etc.
    e.g.

GroupBehavior doesn't work for me in pre4:

<ShellItem GroupBehavior="ShowTabs" FlyoutIcon="stuff.png" Title="Discussion">...
results in:

xxx/Shell/Shell.xaml(14,14): Error: Position 108:14. No property, bindable property, or event found for 'GroupBehavior', or mismatching type between value and property.

and GroupHeaderTemplate doesn't seem to do anything, but, not sure how it's used, or enabled.

I'm trying to add/remove MenuItems, which successfully adds items thru MenuItems.Add(item), but, no result is shown when the flyout is displayed again. Is this the correct approach for doing this?

I don't see any mention of manipulating MenuItems, but, the Shell is pretty much useless to me (and I'm thinking a lot of others, including @puppetSpace above) unless these items can be maintained dynamically based upon your business logic.

I'd agree with dbwelch that being able to programatically change shell in the cs file is very important. Not only for menu items, but also ShellItems & ShellSections.

When I turn Flyout on, and add menu items, I get a hamburger menu in Android, and in iOS if I click in that spot it works, however there is no icon. Any ideas?

@KyleTraynor there is an open issue somewhere for that. You have to manually copy the 3bar.png and [email protected] images to your iOS Resources folder and make sure they are included in the project as bundle items.

The images I found in the source are attached:
3bar 2x
3bar

@melucas Thank you for the help! I was going nuts trying to fix that. Works great.

Do you happen to know how I can set the OffscreenPageLimit for Android when using Shell?

I have top tab pages made by having 4 ShellContents inside of 1 ShellSection, and it works great on iOS, but on android the pages reload when swapping between them which I do not want. Normally with my own tabbedpage, I could set the OffscreenPageLimit to fix this problem, but I cant find a way to do it with Shell.

@davidortinau could we have the option to set the font family on page titles, bottom and top tabs? In every project I have to create custom renderers for ios and android to change fonts.

So, given that since there's been no response to my post on having the ability to actually change the items in the flyout Shell, maybe this functionality isn't in scope, or a maybe, hopefully being considered a bug ?

Not sure how a serious app can use this Shell without this functionality. Only very simple apps don't require the ability to add/change/remove/disable items on their menus based upon either a) context of the user (i.e. authenticated/non-authenticated), or b) varying states of the application that would require it.

Just curious @jassmith, are the folks who created the spec keyed into this forum or is this just for developer feedback?

Btw, other than this one major item, I have implemented the Shell into my code for one app and it's working very well, thank you! But, sadly, will have to pull it out and implement my own flyout if the Shell doesn't have this functionality working/implemented.

@dbwelch, a couple things.
You're posting on the spec, so you probably won't get a response like you wrote opening a new issue. Also, Jason is no longer working on Forms, so calling him out is kinda pointless.

Bottom line, file an issue

@dbwelch @ChaseFlorell I opened an issue here: https://github.com/xamarin/Xamarin.Forms/issues/5428

@davidortinau could we have the option to set the font family on page titles, bottom and top tabs? In every project I have to create custom renderers for ios and android to change fonts.

@jamiewest Submit a feature request! Thanks! https://github.com/xamarin/Xamarin.Forms/issues/new?assignees=&labels=t%2Fenhancement+%E2%9E%95&template=feature_request.md&title=%5BEnhancement%5D+YOUR+IDEA%21

Could the UseSwipeGesture feature implement?
It seem like now ShellItem class not have the ShellAppearance property to opera.
But now In Android ,The Shell's Tabs not like the TabPage(TabPage can swipe as default.)

    <ShellItem.ShellAppearance>
      <MaterialShellAppearance NavBarCollapseStyle="Full" TabBarCollapseStyle="Full" UseSwipeGesture="false">
    </ShellItem.ShellAppearance>

@jingliancui, 崔兄,有没有qq或者微信?

@juepiezhongren Hi, you can join to this qq group for chat with me 313308215

Will we see Shell and visual support coming for UWP upon RTM?

I welcome this idea- regardless of whatever it makes harder because working with navigation pages, master-detail pages, etc. feels way to convoluted. Maybe this is because I come from a web background (have not worked with native APIs much). Customizing the navigation bar, page titles, back button, toolbar items, headers and footers (ListView), etc. come to mind here.

I suppose what I'm requesting is that new features, like *Shell, are shipped with customization and extensibility in mind. There are very few situations we've been in where we didn't need to make a series of renderers, behaviors, triggers, etc. to perform seemingly simple things.

Whatever you guys come up with, please do whatever you can to make it easier for us to make our Xamarin.Forms apps look as good as other native apps! It sounds like this feature will give us a better launchpad for modern-looking XForms apps!

Is there source code that is available to see how this Shell works, instead of having to guess around the spec? For example, what style is used to color the hamburger icon, if it's available. Sorry, new at C#/Xamarin, but, if the code were viewable somewhere, would help tremendously.

@dbwelch you can browse the source code right here on GitHub. Hit "T" and type in Shell to see associated classes. That may not be the best starting point however if you're new to C#/Xamarin. I recommend checking out some of my samples until we get more documentation up:

https://github.com/davidortinau/Gastropods
https://github.com/davidortinau/ShellGallery
https://github.com/davidortinau/TheLittleThingsPlayground

Docs: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell?tabs=android
MSDN Article: https://msdn.microsoft.com/en-us/magazine/mt848639
Blog: https://blog.xamarin.com/xamarin-forms-4-0-preview/

@davidortinau thanks, but, I thought it was just released code that was available, where is the Shell code? I've looked under branches for 4.0, Shell, others, but, it's hiding from me! Thanks!

@pauldipietro Thanks, see it now. @davidortinau I actually have spent a good deal of time on all the links (except LittleThings, which I just downloaded), but, just don't see how to change such a simple thing as the hamburger icon color. It's appearing as purple in my app, but, I don't have a purple color defined anywhere (that I can see). A bit frustrating ;-).

UPDATE: I just found the issue, and, of course, it's some yucky code that exists in the FinishedLaunching to add TintColor. DOH!

Thanks gentlemen, appreciate the assistance!

I have some items showing in the flyout panel which is fine. However, is currently already have a way to hide/not show a Shell item (not the item content). Example, I have a ContentPage and I just want to have the navigation inside the Shell.

<local:DetailPage />

It seems is always adding the item in the Flyout panel/list. And if there is no Title, then it will have an empty stack/placeholder of the item. I have try many ways to hide the item still no luck. Probably someone can help or the feature still not yet available.

Preface: I'm a newb atm. Trying not to be.

@davidortinau So, I've been trying to learn this Shell feature to add navigation, etc. into our first Xamarin.Forms project for our company (woot!) and I'm stuck on trying to figure out if it's possible to pass 1 or more params from a ShellItem to other parts of the application via the new routing functionality. Is this a thing at all? Or must we stick with commanding using MenuItems within a MenuItem collection instead? If we must use a MenuItem to pass 1 or more values from the Flyout level, it would seem we can no longer structure our app with the Shell hierarchy any more since we are using MenuItems instead? Don't we lose that in using MenuItems with command params?

Is there anyone that can chime in on this? If so, I would greatly appreciate it. Basically would love to use Shell, but still be able to tag what ShellItem the user selected upon clicking one to pass that to a ContentTemplate page or whatever is appropriate since a lot of the ShellItems will be navigating to a similar intermediate page to make an OrderType and OrderDepartment dropdown selection first before going to the main Order screen with the appropriate data for the right type and dept.

Also, I apologize if this is the wrong place for this. If so, please point me in the right place. Thanks!

Update:
Maybe I'll just use the MenuItems for now and pass a command param to a ShellViewModel to navigate with the right values for the target page. Now that I think of it, I really won't need to navigate to a tabbed structure from those MenuItems pushing to the ContentTemplate page.

I also was wondering if we can define where MenuItems are located within the Flyout so that the ShellItems don't all pop to the top; and if one day we don't have to define our MenuItems as part of a collection so that they can intermingle with ShellItems like:
MenuItem
ShellItem
ShellItem
MenuItem
ShellItem
MenuItem
...
That, or just make ShellItems able to pass params at some point if they can't already.

I'm with @anthcool and find this an extremely important feature. I was not able to find a way to do this and had to stop using Shell. Just need to be able to pass something to a content page to know which was clicked on.

@anthcool just trying to help and give some suggestion here as what I did at the moment. Create a navigation parameters class which has a readonly Stack<NavigationParameter> as a stack list, i.e.

public class Navigation
{
    readonly Stack<NavigationParameter> _stack = new Stack<NavigationParameter>();
...
    public Stack<NavigationParameter> Parameters => _stack;
}

The NavigationParameter is:

public class NavigationParameter : NameValueCollection { }

You can add parameters before the push when navigating, e.x.:

    var p = new NavigationParameter { { nameof(SomePage), SomeObject } };
    Navigation.Parameters.Push(p);

Once you in the other page, just Peek or Pop the value and checking the key.
Something like above. Hope that helps.

@anthcool just trying to help and give some suggestion here as what I did at the moment. Create a navigation parameters class which has a readonly Stack<NavigationParameter> as a stack list, i.e.

public class Navigation
{
    readonly Stack<NavigationParameter> _stack = new Stack<NavigationParameter>();
...
    public Stack<NavigationParameter> Parameters => _stack;
}

The NavigationParameter is:

public class NavigationParameter : NameValueCollection { }

You can add parameters before the push when navigating, e.x.:

    var p = new NavigationParameter { { nameof(SomePage), SomeObject } };
    Navigation.Parameters.Push(p);

Once you in the other page, just Peek or Pop the value and checking the key.
Something like above. Hope that helps.

Thanks for the idea @rizamarhaban! Really appreciate you chiming in on this. Thank you! I'll check this out here soon. Again, appreciate it!

Very disappointed to learn Shell and Visual don't support UWP.

Is this spec really done?
Why close this just because there's now a Tizen implementation?
I was under the impression that the navigation functionality was still under review.

Still no UWP support. Biggest disappointment I ever had of Xamarin.

@weitzhandler Please email me at paul.[email protected] if you would like to discuss this and UWP in general. We are not actively ignoring the platform, but Android and iOS are receiving the initial implementation and investigations into Shell support for UWP are actively ongoing.

@mrlacey Nah, it's nowhere near done! It just keeps getting closed by related issues. 😄

For all of those asking for UWP support, I took a stab at it: https://github.com/xamarin/Xamarin.Forms/pull/6015

Is there a way to implement a navigation bar template on the content page?
Specifying NavigationPage.TitleView doesn't apply as it did before.
Repo for reference:
https://github.com/InquisitorJax/Xamarin-Forms-Shell

EDIT:
Murphy strikes again - just use Shell.TitleView instead of NavigationPage.TitleView :)

Hello,
In my new project I am using Shell and CollectionView, and I have to say that are great!
One question about Shell

  • there is a way to add a bottom item fixed (fox example a button for user logout)

I see that is possible to add a fixed header (FlyoutHeader and FlyoutHeaderBehavior) but I cant find any info about bottom footer
Thanks!

Hello,
I have another question about RegisterRoute.
My app is rather large, with a considerable number of pages, about 30...
Is really the right way to add the RegisterRoute for each of them?
Routing.RegisterRoute("blabla", typeof(BlaBlaPage)); ... ...
Or is better to use the old way?
var blaPage = new BlaBlaPage (); await Navigation.PushAsync (blaPage);

@matteopiccioni I would recommend doing it like this

Routing.RegisterRoute("blabla", typeof(BlaBlaPage));

and using
gotoasync("blabla")

I realize right now it feels the same but as the features grow it's going to be more relevant to have all of those things operating via the Shell system

Is really the right way to add the RegisterRoute for each of them?

if this becomes a pain point we're looking at adding some features that will just assembly scan for pages or maybe even some compile time features that will generate those routes.

The main issue here is that any type of reflection is going to slow down your app so doing that at startup will cost

@PureWeen thanks for answer
Slow startup time is one of the most annoying problem in xf (for Android)
On startup could I add to routing only the first level of pages (the shellitems pages) and add the others only in after app is started (a sort of Lazy loading of RegisterRoute)?

@matteopiccioni

So if you just do it like this all at once

Routing.RegisterRoute("blabla", typeof(BlaBlaPage));

it's fine. All I was talking about is if we end up building something that makes it so users don't have to do that we'll need to weigh it against performance. Right now Routing.RegisterRoute("blabla", typeof(BlaBlaPage)); doesn't do any reflection so doing it all at once is fine.

all it does is adds a string and type to a dictionary

@jassmith @jamesmontemagno @pierceboggan Wow looks great. Have you seen the Google Contacts application using Pie SDK on a Google Pixel? I love the UI/UX, with no title bar and the hamburger integrated with the top of the app.

Can this suggestion be considered for your Shell since its a pattern that Google is using, with Contacts and Maps, and maybe others?

Thank you for your time and consideration,

Karl

Note that all samples that follow do not use templated ShellContent's, which are discussed elsewhere in the spec. Failure to properly use ShellContents with a ContentTemplate will result in all pages being loaded at startup, which will negatively impact startup performance. These samples are for learning purposes only.
Fortunately using ShellContents with ContentTemplates is usually more concise than not using them.
[...]
A major problem with using the Shell is the ease by which a user can end up loading all pages at the start of their application run. This large frontloaded allocation can result in quite poor startup performance if a large number of content pages are needed. In order to fix this templating should be employed when possible.

To me this sounds like you shouldn't ever use content directly but use templates. This makes sense to me, so why support the direct content approach? (apart from the simplicity, but it's letting people shoot themself in the foot). It sort feels like being able to use direct content is more of a "great when doing a demo - otherwise horrible" feature.

Hi,
I am new here. I am not sure if this is the right place to ask questions, otherwise please direct me where to ask:
I tried to do something similar to the sample specified above:

  <ShellItem Title="My music" ItemsSource="{x:Bind MyMusicModels}" TabLocation="Bottom">
    <ShellItem.ItemTemplate>
      <local:MyMusicItemTemplateSelection />
    </ShellItem.ItemTemplate>
  </ShellItem>

But I got the following errors:

Error XLS0413 The property 'ItemsSource' was not found in type 'ShellItem'.
Error XLS0415 The attachable property 'ItemTemplate' was not found in type 'ShellItem'.

@Elashi so are you hoping to do this idea here
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/bindable-layouts

With ShellItem?

@PureWeen I was hoping to use this idea :) .
Are you suggesting that this idea is not implemented yet?
If it is not implemented yet, I might be interested in working on it.

@Elashi it is not but I could see that being a really powerful feature for MVVM Scenarios

If you want to work on it can you create an issue with the basics of what you're thinking?

So from trial and error... Even though it has comments about gestures in shell 3.2 and its in TheLittlePlayground I cannot for the life of me make Gestures work on ANDROID with the visual package.

Am I missing something in the notes that Shell + gestures only work with iphone?

@davidortinau I know this is just some specs, and it's been closed for a while, but I was hoping you might be able to point me in the right direction since the specs point out that the below task is either completed or on the docket for development:

  • Add API for "submenu" items for ShellContent's ala GPS -> Music -> Open Music app

Currently since I can't get GroupHeaders to work, I'm looking to rework my FlyoutMenu to sort into 6 main groups, and then have a submenu appear full of FlyoutItems that navigate me to the routing I've predetermined.

My use-case is that I have 50+ options to display and putting that in a scrolling state is not UI friendly, but each option to be displayed is something that I need to allow my users to get to efficiently without having to scroll endlessly. Sorting into groups based on the over-arching theme of each option makes the most sense from a UI/UX standpoint.

Can you shed some light on where that stands in terms of development / production? - or point me in the direction of a code base that implements it so I can learn? (I've only been with Xamarin for 1 month, so I'm still new to some of the resources available).

@TheBaileyBrew

I just Googled this repo with something that could work for your scenario most likely. It won't be Shell, but you could use it in a MasterDetailPage setup probably.

https://github.com/ishrakland/ListViewWithSubListView/

Also, they just moved and updated a lot of their course material to MSFT Learn (that I'm running through myself to fill in the gaps). That's found here: https://docs.microsoft.com/en-us/learn/browse/?products=xamarin

I'd try and run through the above. Best of luck and welcome aboard!

Hi guys i want to pick file or photos from gallery or external storage in
xamarin forms who to pick file it? The file is only .PDF extension. To
select both files I use one button so pleases help me!!!

On Thu, May 23, 2019, 19:41 Anthony Cool notifications@github.com wrote:

@TheBaileyBrew https://github.com/TheBaileyBrew

I just Googled this repo with something that could work for your scenario
most likely. It won't be Shell, but you could use it in a MasterDetailPage
setup probably.

https://github.com/ishrakland/ListViewWithSubListView/


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/xamarin/Xamarin.Forms/issues/2415?email_source=notifications&email_token=AK7KSYK4N3XIVP3IHOBE2P3PW3CKJA5CNFSM4EZ4GB52YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWCZR7Y#issuecomment-495294719,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AK7KSYI5XKMXD7FC7HZH45LPW3CKJANCNFSM4EZ4GB5Q
.

Hey Guys, i want to add tabs on basis of condition so how can i add tabs in Shell using C# not in Xaml as well how to add menu itms.

@TheBaileyBrew

is this what you're looking for?
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/flyout#flyout-display-options

@BeleShew your question is probably better suited for stackoverflow or over at forums.xamarin.com

@PWaliaDev you would do that through the various Items collections that are part of shell

Shell.Items.Add(new ShellItem())
new ShellItem().Items.add(new ShellSection())
new ShellSection().Items.Add(new ShellContent())

Though I'm assuming if we fixed this issue
https://github.com/xamarin/Xamarin.Forms/issues/5428

that would suit your scenario?

@PureWeen -- I've got the display options set per your link, but what I'm struggling with is closer to what @BeleShew is dealing with (creating/removing flyout items on a per user basis)

Fixing #5428 would fit what I'm looking to achieve.

My app has users with a multitude of roles/access and I need to programmatically show menu options only to those users who are authorized (I don't want users to see what they _can't_ do, only what they can.

Although I've been playing around with this, trying to figure out if it's possible to inspect my menu options and add rather then hide like this code does (but I'd have to iterate against every possible route and menu option which would eat up load time:

foreach (var item in this.Items)
        {
            if (item is FlyoutItem)
            {
                var removeSections = new List<ShellSection>();
                var fi = item as FlyoutItem;
                foreach (var child in fi.Items)
                {
                    if (child.Route == "NOT_AUTHORIZED_KEY")
                        removeSections.Add(child);
                }
                foreach (var s in removeSections)
                    fi.Items.Remove(s);
            }
        }

Shell is great in theory but not in practical terms without these must have features.

  1. Add/remove shell items dynamically based on user role
  2. Login/Logout Scenario or two separate navigation route based on conditions.
  3. Optionally, Support for other MVVM frameworks like Prism

Can't use Shell in Business oriented apps until feature 1 and 2 are provided.

@Im-PJ Why do you think 1 and 2 aren't possible? (pretty sure they are)

3 is in progress and tracked here.

Does anyone know if it's possible to get a tap event from an App Shell tab?
related forum question: https://forums.xamarin.com/discussion/159748/app-shell-pop-to-root-on-tab-tap

Completely agree with @Im-PJ, and don’t understand how these features are not specifically provided for. It’s a main reason for a tool like Shell. Anyone can build a slide out menu!

@dotMorten maybe you can do 1 or 2 through extensive C# and hacking, but there are NO examples or mention of binding/disabling/hiding/adding Shell items at runtime that I can find. Seems that dynamic capabilities would have been a major goal of this tool. Creating an XML representation, along with some pathing features, is bare minimum, enough to give to the marketing folks, but not sufficient to actually use in a real, full featured mobile app.

@Im-PJ

can you expand a little bit on how these are different?

Add/remove shell items dynamically based on user role
Login/Logout Scenario

Currently you can do a Login/Logout Scenario by using a TabBar or hiding the flyout navigation if you are on a login page

<TabBar Route="LoggedOut">
<LoginPage>
</TabBar>

<FlyoutItem Route="LoggedIn"></FlyoutItem>
<FlyoutItem></FlyoutItem>
<FlyoutItem></FlyoutItem>
<FlyoutItem></FlyoutItem>

If you're on the Login Page the only way to navigate away is through code.

Work is being done here to expose an IsVisible bindable property
https://github.com/xamarin/Xamarin.Forms/tree/shell_isvisible

It just needs a little refining before creating a PR

two separate navigation route based on conditions.

Can you provide examples of what you are trying to do and cannot do currently?

hoi1
I'm using the Xamarin.Form Shell

Link Sample: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/flyout

Please help me. How to show the Tabbar in the About page?

I need To have two shell pages at the same time.
One for a flayout menu with page as home, settings, logout, etc
One for tabbedpages that should be pushed from home
For now I have to use the 'old way'

I need To have two shell pages at the same time.
One for a flayout menu with page as home, settings, logout, etc
One for tabbedpages that should be pushed from home
For now I have to use the 'old way'

If using Tabbedpage, can't show Flyout . I want to show Flyout and Tabbar on this time.

I put all the pages in the so that the pages display the Tabbar, But I want to only have 4 elements in the tabbar (don't want to show More Tab). How do to do?

<shell>
<flyoutitem route="animals" flyoutdisplayoptions="AsMultipleItems">
<shellcontent route="cats"/>
<shellcontent route="dogs"/>
<shellcontent route="monkeys"/>
<shellcontent route="elephants"/>
<shellcontent route="bears"/>
<shellcontent route="about"/>
</flyoutitem>
</shell>

I need To have two shell pages at the same time.
One for a flayout menu with page as home, settings, logout, etc
One for tabbedpages that should be pushed from home
For now I have to use the 'old way'

If using Tabbedpage, can't show Flyout . I want to show Flyout and Tabbar on this time.

I put all the pages in the so that the pages display the Tabbar, But I want to only have 4 elements in the tabbar (don't want to show More Tab). How do to do?

<shell>
<flyoutitem route="animals" flyoutdisplayoptions="AsMultipleItems">
<shellcontent route="cats"/>
<shellcontent route="dogs"/>
<shellcontent route="monkeys"/>
<shellcontent route="elephants"/>
<shellcontent route="bears"/>
<shellcontent route="about"/>
</flyoutitem>
</shell>

Unfortunately I cant use Shell
I still have MasterDetailPage and TabbedPage in the same app (in iOS I have top tabbed pages using Naxam.TopTabbedPage.Forms plugin)
This was my old ticket

Was this page helpful?
0 / 5 - 0 ratings