<p>Xamarin.Forms.Shell 规范</p>

创建于 2018-04-10  ·  199评论  ·  资料来源: xamarin/Xamarin.Forms

Xamarin.Forms 外壳规范

让新开发人员简单明了地获得完整的应用程序体验,该体验结构正确,使用正确的元素,只需很少的努力,并在默认情况下获得清晰的路径。

Shell 在某些方面是一个固执的 API,它并不总是将每个值都默认为某个 .Default,它可能会根据运行平台而改变。 相反,它可能会设置一个值,然后在所有平台上都遵守该值,而不管平台默认值是什么。

注意:绘图规范移至:#2452

视觉处理

需要截图...

Shell 层次结构

一开始理解 Shell 层次结构可能会让人不知所措。 它代表了一个复杂的层次结构,并提供了强大的机制来最小化创建丰富层次结构所需的样板 xaml 的数量。

因此,当第一次学习 shell 时,最简单的方法是先学习不使用快捷方式,然后再介绍快捷方式,看看如何轻松地最大限度地减少 XAML 的编写量。

请注意,后面的所有示例都不使用模板化的 ShellContent,这在规范的其他地方进行了讨论。 未能正确使用带有 ContentTemplate 的 ShellContents 将导致在启动时加载所有页面,这将对启动性能产生负面影响。 这些示例仅用于学习目的。

幸运的是,将 ShellContents 与 ContentTemplates 一起使用通常比不使用它们更简洁。

没有捷径

这些样本中的许多看起来会不必要地复杂,而实际上它们确实如此。 在下一节中,这些将得到简化。

一个简单的单页应用

<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

通过在 MainPage 上设置Shell.NavBarVisible="false"可以完全隐藏顶部栏。 Flyout 在此模式下看起来也相当稀疏,因此在此示例中被禁用。

带有底部标签的两页应用程序

<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

通过将ShellSection部分添加到ShellItem出现另一个底部选项卡。 设置适当的标题和图标可以控制选项卡项目的标题和图标。

带有顶部和底部选项卡的两页应用程序

<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

通过添加第二次ShellContent to the ShellSection ode添加顶部选项卡栏,可以在选择底部选项卡之间翻转页面。

使用弹出式导航的两页应用程序

<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

此示例中重新启用了弹出按钮。 在这里,用户可以使用浮出控件作为中介在两个页面之间切换。 还添加了标题以看起来不错。

使用速记语法

现在已经显示并简要解释了层次结构的所有级别,可以在定义层次结构时保留大部分不需要的包装。 Shell只包含ShellItem s,它只包含ShellSection s,而后者只包含ShellContent s。 但是,存在隐式转换运算符以允许自动向上包装。

一个简单的单页应用

<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>

通过隐式包装,页面会自动一直包装到ShellItem 。 不需要写出所有的中间层。 TitleIcon Page将绑定到任何隐式生成的父项。

带有底部标签的两页应用程序

<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>

这些页面现在隐式地包含在 ShellContent 和它们自己的 ShellSections 中。 这会导致创建两个不同的选项卡,就像以前一样。

带有顶部和底部选项卡的两页应用程序

<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>

使用弹出式导航的两页应用程序

<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>

这里隐式包装一直到 shell item,所以我们不需要自己做任何包装。

导航模型

推送导航

所有导航都基于视图的 .Navigation 属性。 推送进入显示的当前 ShellSection。 这意味着在推送事件中,顶部标签将消失,底部标签将保留。

URI导航

Shell 可以使用上面讨论的标准 Navigation 属性进行导航,但是 Shell 引入了更方便的导航机制。

导航 URI 的格式如下:

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

shell 层次结构中的所有项目都有一个与之关联的路由。 如果开发者未设置路由,则在运行时生成路由。 运行时生成的路由不能保证在应用程序的不同运行中稳定,因此对深度链接没有用。

处理后退按钮

由于 Shell 将处于不必使用本机控件的令人羡慕的位置,因此可以而且应该支持所有形式的后退按钮覆盖。

正确处理后退按钮需要支持以下功能:

  • 拦截交互并阻止它们
  • 用其他东西替换后退按钮
  • 需要时完全隐藏后退按钮
  • 为软件和硬件按钮工作

为了便于使用,API 需要细化到页面级别,但也能够在更一般的级别上进一步处理堆栈。

代码示例和 API

样品

<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>

使用 Shell 的单页应用程序

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

单组选项卡应用程序(无弹出)

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

弹出窗口中的多个页面没有选项卡

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

单页可搜索应用程序

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

```csharp
公共类 MyPage : ContentPage
{
公共类 MyPageSearchHandler : SearchHandler
{
公共 MyPageHandler()
{
SearchBoxVisibility = SearchBoxVisibility.Collapsed;
IsSearchEnabled = true;
Placeholder = "搜索我!";
}

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
}

}

公共我的页面 ()
{
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);
}

描述

附加属性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| SearchHandlerProperty | 用于定义页面级搜索功能的附加属性。 可以附加在层次结构中的多个点。 使用此处定义的一些功能https://material.io/guidelines/patterns/search.html#search -in-app-search |
| 返回按钮行为 | 允许完全覆盖后退按钮的行为方式。 适用于屏幕和物理后退按钮。 |
| 弹出行为 | 定义 Flyout 应如何呈现自身。 这可以附加到ShellItem s、 ShellContent s 或Page s 以覆盖默认行为。 |
| NavBarVisibleProperty | 在Page上设置的属性用于定义 NavBar 在呈现时是否应该可见 |
| SetPaddingInsetsProperty | 在Page上设置此属性将导致其Padding设置为使其内容不会在任何 Shell chrome 下流动。 |
| TabBarVisibleProperty | 在Page上设置的属性用于定义 TabBar 在呈现时是否应该可见 |
| 标题视图属性 | 属性设置在Page以定义TitleView |
| ShellBackgroundColorProperty | 描述壳的铬元素应该使用的背景颜色。 此颜色不会填充在壳的内容后面。 |
| ShellDisabledColorProperty | 着色被禁用的文本/图标的颜色 |
| ShellForegroundColorProperty | 在外壳中为普通文本/图标着色的颜色 |
| ShellTabBarBackgroundColorProperty | 覆盖 TabBar 的 ShellBackgroudnColor。 如果未设置,将使用 ShellBackgroundColor |
| ShellTabBarDisabledColorProperty | 覆盖 TabBar 的 ShellDisabledColor。 如果没有设置 ShellDisabledColorProperty 将被使用 |
| ShellTabBarForegroundColorProperty | 覆盖 TabBar 的 ShellForegroundColorProperty。 如果没有设置 ShellForegroundColorProperty 将被使用 |
| ShellTabBarTitleColorProperty | 覆盖 TabBar 的 ShellTitleColorProperty。 如果未设置,将使用 ShellTitleColorProperty |
| ShellTabBarUnselectedColorProperty | 覆盖 TabBar 的 ShellUnselectedColorProperty。 如果没有设置 ShellUnselectedColorProperty 将被使用 |
| ShellTitleColorProperty | 当前页面标题使用的颜色 |
| ShellUnselectedColorProperty | 用于 shell chrome 中未选中文本/图标的颜色 |

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 当前项目 | 当前选中的 ShellItem |
| 当前状态 | Shell 的当前导航状态。 将此状态传递回 GoToAsync 将导致 Shell 返回导航回状态。 |
| 弹出背景颜色属性 | 弹出菜单的背景颜色 |
| 弹出行为 | 为Shell设置默认的FlyoutBehavior Shell 。 |
| 弹出页眉 | 用作浮出控件标题的对象。 如果FlyoutHeaderTemplate不为空,则将其作为BindingContext传递给膨胀的对象。 如果FlyoutHeaderTemplate为空且FlyoutHeaderView ,则将直接使用。 否则,它将通过调用 ToString() 并显示结果来显示。 |
| FlyoutHeaderBehavior | 设置当需要滚动 Flyout 以显示内容时FlyoutHeader的行为。 |
| FlyoutHeaderTemplate | 用于为 Flyout 创建标题的模板。 |
| FlyoutIsPresented | 获取或设置 Flyout 是否当前可见 |
| 组头模板 | 如果ShellItem请求在弹出窗口中显示为一组选项卡,则DataTemplate用于显示组标题。 如果为空,则不显示标题。 |
| 项目 | Shell 的主要内容。 项目定义将在弹出窗口中显示的项目列表以及在选择侧边栏项目时将显示的内容。 |
| 项目模板 | DataTemplate用于在弹出窗口中显示Items集合中的项目。 允许开发人员控制浮出控件中的视觉效果。 |
| 菜单项 | MenuItem的集合,它们将显示在它们自己部分的弹出窗口中。 |
| 菜单项模板 | 该DataTemplate来使用显示的时候MenuItem在弹出。 |
| 路线 | 执行深层链接时处理此元素的路由部分。 |
| 路由主机 | 放置在创建深层链接时生成的 URI 的主机部分中的字符串 |
| 路线图 | 放置在创建深层链接时生成的 URI 的方案部分中的字符串 |

公共方法:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 转到异步 | 导航到ShellNavigationState 。 返回一个任务,该任务将在动画完成后完成。 |

公共活动:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 导航 | 由于用户交互或开发人员调用 API, Shell即将执行导航。 如果可能,开发者可能会取消此处的导航。 |
| 导航 | Shell已经完成了一个导航事件。 |

ShellItem集合

ShellItem的集合

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

菜单项集合

MenuItem的集合

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

ShellSection集合

ShellSection的集合

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

外壳内容集合

ShellContent的集合

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

ShellNavigatingEventArgs

EventArgs用于描述即将发生的导航事件。 如果开发人员愿意, ShellNavigationEventArgs也可用于取消导航事件。

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

  public ShellNavigationState Target { get; }

  public ShellNavigationSource Source { get; }

  public bool CanCancel { get; }

  public bool Cancel ();
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 当前 | Shell的当前 NavigationState。 使用此ShellNavigationState调用GoToAsync ShellNavigationState将有效地撤消此导航事件。 |
| 目标 | 此导航事件完成后Shell将处于的状态。 |
| 来源 | 触发此事件的导航类型。 可能设置了多个标志。 |
| 可以取消 | 导航事件是否可取消。 并非所有活动都可以取消。 |

公共方法:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 取消 | 取消当前导航事件。 如果取消成功,则返回 true。 |

ShellNavigatedEventArgs

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

  public ShellNavigationState Current { get; }

  public ShellNavigationSource Source { get; }
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 上一页 | Shell的先前 NavigationState。 |
| 当前 | 当此导航事件完成时, Shell所处的新状态。 |
| 来源 | 触发此事件的导航类型。 可能设置了多个标志。 |

外壳导航状态

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);
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 位置 | 描述Shell导航状态的 Uri |

构造函数:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| (无效) | 使用空位置创建一个新的ShellNavigationState |
| (字符串) | 创建一个新的ShellNavigationState ,位置设置为提供的string |
| (乌里) | 创建一个新的ShellNavigationState ,位置设置为提供的Uri |

外壳导航源

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

基壳项

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; }
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 飞出图标 | 在弹出窗口中显示时使用的默认图标。 如果未设置,将默认为 Icon。 |
| 图标 | 显示在 chrome 部分不是 Flyout 的图标。 |
| 已检查 | 如果BaseShellItem当前在弹出窗口中被选中(因此应该突出显示)|
| 已启用 | 如果BaseShellItem在 chrome 中可选 |
| 路线 | 相当于设置 Routing.Route |
| 标题 | 在 UI 中显示的标题 |

壳组项

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

  public FlyoutDisplayOptions FlyoutDisplayOptions { get; set; }
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 弹出显示选项 | 控制此项及其子项在弹出窗口中的显示方式 |

外壳项目

[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);
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 当前项目 | 选定的ShellSection 。 |
| 项目 | ShellSectionCollection是 ShellItem 的主要内容。 该集合定义了 ShellItem 中的所有选项卡。 |

外壳部分

[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);
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 当前项目 | 选定的ShellContent的 ShellSection。 |
| 项目 | ShellContentCollection是 ShellSection 的根内容。 |
| 堆栈 | ShellSection 上当前推送的导航堆栈。 |

方法:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 转到异步 | 由深层链接用于导航到已知位置。 大多数情况下不需要直接调用。 |
| 获取导航堆栈 | 返回当前导航堆栈 |
| OnInsertPageBefore | 在调用INavigation接口InsertPageBefore方法时调用 |
| OnPopAsync | 调用INavigation接口PopAsync方法时调用 |
| OnPopToRootAsync | 调用INavigation接口PopToRootAsync方法时调用 |
| OnPushAsync | 在调用INavigation接口PushAsync方法时调用 |
| OnRemovePage | 当调用INavigation接口RemovePage方法时调用 |

外壳内容

[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);
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 内容 | ShellContent 的内容。 通常一个ContentPageBindingContextPage由充气ContentTemplate |
| 内容模板 | 用于动态膨胀ShellContentContent属性将在通货膨胀后设置为BindingContext 。 |
| 菜单项 | 当此 ShellContent 是呈现的页面时要在弹出窗口中显示的项目 |

搜索处理器

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();
}

特性:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 清除图标帮助文本 | 清除图标的可访问帮助文本 |
| 清除图标名称属性 | 用于屏幕阅读器的清除图标的名称 |
| 清除图标 | 显示的图标用于清除搜索框的内容。 |
| ClearPlaceholderCommandParameter | ClearPlaceholderCommand |
| 清除占位符命令 | 点击 ClearPlaceholder 图标时执行的命令 |
| 清除占位符已启用 | ClearPlaceholderIcon 的启用状态。 默认为真。 |
| 清除占位符帮助文本 | 清晰占位符图标的可访问帮助文本 |
| 清除占位符图标 | 搜索框为空时显示在ClearIcon位置的图标。 |
| 清除占位符名称 | 用于屏幕阅读器的清晰占位符图标的名称 |
| 命令参数 | Command |
| 命令 | 确认查询时执行的ICommand
| 显示成员路径 | 为ItemsSource中的每个数据项显示的属性的名称或路径。 |
| IsSearchEnabled | 控制搜索框的启用状态。 |
| 项目来源 | 要显示在建议区域中的项目集合。 |
| 项目模板 | 建议区域中显示的项目的模板。 |
| 占位符 | 搜索框为空时显示的字符串。 |
| QueryIconHelpTextProperty | 查询图标的可访问帮助文本 |
| QueryIconNameProperty | 用于屏幕阅读器的查询图标的名称 |
| 查询图标 | 用于向用户表明搜索可用的图标 |
| 查询 | 搜索框中的当前字符串。 |
| 搜索框可见性 | 定义Shell s 镶边中搜索框的可见性。 |
| 显示结果 | 确定是否应在文本输入时预期搜索结果 |

受保护的方法:

| API | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| OnClearPlaceholderClicked | 每当按下 ClearPlaceholder 图标时调用。 |
| OnItemSelected | 每当用户按下搜索结果时调用 |
| OnQueryConfirmed | 每当用户按下 Enter 键或确认他们在搜索框中的输入时调用。 |
| OnQueryChanged | 当Query更改时调用。 |

搜索框可见性

public enum SearchBoxVisiblity
{
  Hidden,
  Collapsable,
  Expanded
}

| 价值 | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 隐藏 | 搜索框不可见或不可访问。 |
| 可折叠 | 搜索框是隐藏的,直到用户执行一个操作来显示它。 |
| 展开 | 搜索框显示为完全展开的条目。 |

返回按钮行为

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 | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 图标覆盖 | 更改用于后退按钮的图标。 |
| 文本覆盖 | 如果使用文本,则更改用于指示向后导航的文本。 |
| 命令 | 提供替换命令以在按下后退按钮时调用。 |
| 命令参数 | 与Command一起使用的命令参数 |

弹出显示选项

确定ShellGroupItem在 FlyoutMenu 中的显示方式。

  public enum FlyoutDisplayOptions
  {
    AsSingleItem,
    AsMultipleItems,
  }

| 价值 | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| AsSingleItem | ShellGroupItem将在弹出窗口中显示为单个条目。 |
| AsMultipleItems | ShellGroupItem将显示为一组项目,浮出控件中的每个子项对应一个。 |

弹出标题行为

滚动时控制 FlyoutHeader 的行为。

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

| 价值 | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 默认 | 平台默认行为。 |
| 固定 | 标题始终保持可见和不变 |
| 滚动 | 当用户滚动菜单时,标题滚动出视图 |
| CollapseOnScroll | 标题仅在用户滚动时折叠为标题 |

弹出行为

public enum FlyoutBehavior
{
  Disabled,
  Flyout,
  Locked
}

| 价值 | 说明 |
| -----------| -------------------------------------------------- -----------------------------------------|
| 残疾 | 用户无法访问浮出控件。 |
| 弹出 | 浮出控件作为普通浮出控件工作,可由用户打开/关闭。 |
| 锁定 | Flyout 被锁定,用户无法关闭,它不会覆盖内容。 |

数据模板扩展

此扩展可快速将类型转换为 ControlTemplate。 这对于模板将被指定为的情况很有用

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

然后可以将其压缩为

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

什物

当您在 Flyout 中选择已推送到的选项卡时会发生什么?

这相当于聚焦选项卡并在其上调用 PopToRoot。

当我切换 ShellItems 并且旧 ShellItem 的 ShellContent 的 backstack 上有项目时会发生什么

如果旧的 ShellItem 被模板化,则返回堆栈将丢失。 如果 ShellItem 没有被模板化,则 BackStack 保持不变,当切换回旧的 ShellItem 时,backstack 将被正确反映。 但是,如上述答案所示,切换回可能会清除 backstack。

有效加载页面

使用 Shell 的一个主要问题是用户可以轻松地在应用程序运行开始时加载所有页面。 如果需要大量的内容页面,这种大的前置分配会导致启动性能非常差。 为了修复此模板,应尽可能使用。

模板化的 ShellContents

模板外壳选项卡项目是可用的模板的最细粒度形式,幸运的是,它也是最容易做到的。 拿下面的外壳。

<?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>

当这个 Shell 加载时,所有 9 个页面将同时膨胀。 这是因为没有使用模板。 要使用基本模板,我们可以将其转换为:

<?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>

页面现在仅根据需要加载,也可以根据需要卸载。 如果需要,ShellItem 本身也可以使用集合和 DataTemplateSelector 进行模板化,这甚至可以防止必须急切地加载 ShellContents,但是这在很大程度上是不需要的,并且模板化 ShellItem 对于具有大量其他类似选项卡的 ShellItems 更有用. 模板化 ShellContent 应该是为性能问题提供模板化的关键领域。

重构 Google Play 商店用户界面

请注意,这并不是对应用程序编码的最佳方式的演示,而是将 GPS 用户界面推到一起的最简洁格式。 它也不会尝试使用 ViewModels 和 DataTemplateSelector 来虚拟化相关页面。 这意味着这将是非常糟糕的表现,因为所有页面都将在应用程序启动时加载。 读者被警告。

假设所有页面内容都正常工作,这只是为了获得 chrome 的一般概念。

外壳.xaml

正确的实现方法是为每个页面使用 ShellItems 并设置 ItemsSource 和 ItemTemplate。 这将允许每个页面仅在需要时加载并在不再需要时卸载。

<?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>

店铺页面

<?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>

并添加搜索栏。

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 ());
  }  
}

等等等等正确设置颜色和内容。

对于像设置页面这样的页面,在按下后退按钮之前不应访问弹出窗口:

<?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>

去做

  • [x] 为搜索框添加API
  • [x] 为 ContentSafeArea 处理添加 API
  • [x] 增加浮动菜单API
  • [x] 为窗口菜单项添加 API
  • [x] 为小吃店添加 API
  • [x] 添加导航中断API
  • [x] 为底部工作表添加 API
  • [x] 添加 API 以定位 FAB
  • [x] 添加故事让导航思路更清晰(部分完成)
  • [x] 添加 LeftBarButton 样式 API
  • [x] 添加从 ShellContent 获取 Back Stack 的机制
  • [x] 添加用于根据所选选项卡更改功能区颜色的 API
  • [x] 为 SearchHandler 添加可选的建议支持
  • [x] 添加支持将始终扩展的搜索栏与搜索栏配置为图标
  • [x] 添加用于从 MaterialShell 类获取“当前”页面的 API。 某些导航场景需要。
  • [x] 添加用于将“状态”保存到后台堆栈的 API
  • [x] 添加 API 以阻止弹出框出来
  • [x] 为 ShellContent 的 ala GPS -> 音乐 -> 打开音乐应用程序的“子菜单”项添加 API
  • [x] 为CancelPlaceholder 命令和图标添加API(通常用于语音搜索的麦克风图标)
  • [x] 转场 API
  • [x] 弄清楚如何处理 INavigation
  • [ ] 扩展 Bottom Sheet API 以匹配 Google Maps 功能
  • [x] 用于处理 Flyout 演示的 API
  • [ ] 需要时禁用弹出手势的 API
  • [ ] 大标题 API
  • [ ] 转换 API

问题

ISearchHandler [已修复]

这个界面做了很多事情,更糟糕的是,随着时间的推移,它可能需要扩展。 因此,它很可能应该是用户可以实现的抽象基类。 这不幸意味着又一次对象分配。 然而,它在未来保持灵活性。 这种变化很可能会发生。

浮动菜单

附件 API 有点繁重,可能会让用户感到困惑。 更糟糕的是,它可能无法很好地映射到所有平台以确保附件适用于动画。 需要做更多的工作来验证这个 API。

shell enhancement ➕

最有用的评论

伙计们,昨天 Jason 和我自己讨论了如何改进这个规范,我们将做一个大的更新,我们把它分成不同的问题。

所有199条评论

让我们继续讨论这个话题,因为我们真的需要听取您,我们的开发人员社区的意见!

首先,感谢@jassmith努力捕捉到这一点,并为我们在这里公开讨论提出了一个建议。

我将分享我的一些想法,提出一些愚蠢的问题,并提出一些希望不是太引导性的问题。 作为 Xamarin.Forms 的程序经理,我经常不得不以这样一种方式提问,这听起来好像我没有任何线索(有时我没有),但实际上我只需要听你说把话放在嘴里。

我喜欢这个提案中的一些内容,因为我可以看到它们如何解决我一直在与你们中的许多人讨论的一些问题,我们正在努力解决。

我也有保留。

我将在这里以几个关于 Shell 概念和开发人员体验的一般思路开始。

应用体验

获得结构合理的完整应用程序体验,使用正确的元素,只需很少的努力,并且默认情况下良好的清晰路径。

如果我使用这种方法在顶层描述我的应用程序,我会得到:

  • 一个应用程序的主题在每个平台上看起来都一样
  • 材料设计(在这种情况下)模式默认开启
  • 通过配置启用的最新导航模式
  • 我不必费力自定义 Entry 或 Button 以在 iOS 和 Android 以及 UWP 上看起来相同?

那是准确的吗? 我应该强调的其他好处?

而不是App我有MaterialShell 。 我需要学习/采用新的顶级应用程序范式才能从中受益吗?

一旦我进入我的应用程序,我就回到了ContentPage ,对吗? 但是我所有的Button s 和Entry s 都是材料丰富的,而且很漂亮。 我仍然可以使用OnPlatform等来使外观(或行为)在另一个平台上有所不同吗?

从现有应用程序到使用这个“shell”,我的迁移路径是什么样的? 我介绍了新的MaterialShell ,描述了我希望我的应用程序的结构和外观,然后运行它来看看新的优点?

定制

如果我喜欢Flyout或菜单项的外观,但我需要调整它们以匹配我的设计师组合,我有哪些选择? 在什么时候我会说“呃,我应该自己完成这一切”并将我拥有的内容移动到标准的 Xamarin.Forms 应用程序结构?

如果我必须完全放弃MaterialShell ,我会失去所有的造型优势吗,我又回到了我开始的地方(就像今天一样), Entry在 iOS、Android 和 UWP 之间看起来完全不同? 我不想。

有一个我期待的临界点。 在我使用这种方法快速开始之后,我会遇到一些限制并需要探索我的选择。 它们是什么,在什么时候我最好不要使用MaterialShell

问题

我将向所有阅读的人提出几个问题来结束第一条评论。

  • 该提案试图解决的问题是否明确定义?
  • 这是你分享的问题吗?
  • 当您阅读本规范时,您认为这会为您解决以前项目中遇到的哪些问题?

如果可能,截图/设计图像会更好。

也看看这个:

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

@jassmith如果整个想法以图像的形式呈现,那就太好了。 感谢为制定规范所做的努力。 我的问题可能不正确。

我的查询是

  • 平板电脑支持,应用程序适应不同布局的响应没有得到解决。
  • 从当前模型迁移到新模型是否具有挑战性? 从应用程序开发人员的角度和 Xamarin Forms 贡献者的角度来看。
  • 我同意大多数应用程序需要单个 UI(因为我们有时必须编写大量自定义渲染器来实现相同的 UI 概念)而不考虑平台细节,新方向是否会删除所有现有功能,就像我们仍然会开发 Xamarin.Forms具有特定于平台的 UI 的应用程序,否则每个人都将被迫采用新标准。
  • 渲染器概念是否仍然存在于 MaterialShell 中
  • 我们真的可以说,在 iOS 中,我们希望以这种方式呈现吗? Flutter 有适用于 Android 的 Cupertino Styles(苹果 UI)和适用于 iOS 的 Android UI。 Xamarin Forms 将朝哪个方向移动。 开发人员是否拥有 Flutter 现在提供的那种能力。

这是否还包括类似于 TextInputLayout 的内容以支持浮动标签/占位符以及错误消息? 如果是,那么我认为Binding应该扩展为包含类似于 wpf 的 'ValidateOnDataErrors`。

在这里查看我的实现
https://github.com/XamFormsExtended/Xfx.Controls/blob/develop/src/Xfx.Controls/XfxBinding.cs

另外,我想知道 MaterialShell 是否应该扩展 Shell,以便可以为 iOS 外观创建一个 HumanInterfaceShell。

@ChaseFlorell这也将是我的评论。 Material 很棒,但如果我们想编写自己的 shell 来满足特定的 UI 需求,那就是另一回事了。

@davidortinau@jassmith

感谢您整理此规范并允许我们提供反馈。

该提案试图解决的问题是否明确定义?

是的。 导航系统并未完全在 Xamarin Forms 中开发,因此如何完成或完全绕过它是一个开放式问题。

这是你分享的问题吗?

是的。

当您阅读本规范时,您认为这会为您解决以前项目中遇到的哪些问题?

我将通过说我认为它不会解决问题来回答这个问题。 我们的特殊问题是当前的导航系统过于僵化,而不是不够严格。 对我们来说最清楚的例子是 TabbedPage。 没有 TabbedView 视图,所以如果我们想要在我们的应用程序中使用选项卡,我们必须使用 TabbedPage。 因此,整个屏幕必须由 TabbedPage 占据,我们不能将空间用于自己的按钮或我们可能想要放在屏幕上的其他控件。 我的建议是将更多功能 _out of_ Pages 移至 Views,而不是将 Pages 中的功能移至更高层。

FloatingMenu 和 FlyoutBehavior 之类的东西让我感到害怕,因为它们暗示导航将被进一步硬编码到 Xamarin.Forms 系统中,并且软件开发人员将失去进一步的控制权。 我可以看到采用更标准化的方法的一些价值,但这肯定会付出代价。

我们一直致力于其他基于 XAML 的技术,如 Silverlight、WPF 和 UWP。 在这些技术中,我们有一个更加开放的方法,我们能够定义更多导航的工作方式。 最近,我们聘请了一位 UI/UX 顾问。 他不知道 XF 的怪癖。 我们只是请他根据我们软件的功能为我们构建一些屏幕。 由于没有 TabbedView 之类的事情,他推荐的大部分内容都无法实现。 我担心这个框架不会让导航变得更容易,反而会让 UX/UI 设计师给我们的设计更难实现。

我要说的另一件事是,这个框架在其他 XAML 平台中看起来是前所未有的,我想说优先级应该是提供跨平台的标准化,而不是提供其他平台不兼容的新框架。 我们目前正在构建三个平台:Silverlight、Xamarin.Forms 和 WPF。 我们需要的是跨这些平台的标准化,以减少偏差,而不是更多。

@迪兰伯里

如果我们想编写自己的 shell 来满足特定的 UI 需求,那就是另一回事了。

是的。 这是我所关心的。 每个应用程序都有自己的特定用例,而更严格的应用程序可能会使其变得更难——而不是更容易实现这些。

还有这个问题: https :

我将回应上述内容,并询问手势和指针将如何发挥 irt shape 原语的作用?

一般的评论是,对于添加到系统中的每一行代码,添加错误代码的机会超过 3 次。 Xamarin Forms 中已经有很多需要修复的错误。 更多的代码意味着添加错误的机会呈指数增长。 会有更多的bug。 我觉得 XF 团队应该努力减少代码库的大小,而不是增加它。 减少代码库是降低错误发生可能性的唯一方法。

为什么要再次发明新事物而不是修复现有错误并首先确保一切都坚如磐石?

对我来说,它已经被触及,但导航是 Xamarin Forms 中最大的单一绊脚石,在过去三年中让我感到最心痛。

MasterDetail 模式的导航在所有三个平台上都不一致,导致汉堡包出现许多问题,迫使您推送页面模态,然后您必须实现自定义导航栏,因为您无法添加回来,但动画在 Android 上看起来很糟糕(即使在医学博士)。

  • 理想情况下,在许多情况下,您应该能够选择退出并使用您自己的 ContentView 覆盖导航栏的内容。 PlatformSpecifics 最初被认为是允许定位工具栏项目的东西(早在我与 Bryan 交谈时),但后来发现它的用途有限。

  • 能够覆盖页面弹出动画等框架内容

很多建议看起来非常有用,只要您可以在特定页面中使用 material shell 并且它不是应用程序范围内的代码就非常有用。 这当然是我们会使用的东西,因为目前我一直在对我们的 UX 人员说“这是 Xamarin Forms 的一个限制”(就像我在之前的角色中所做的那样)。 我敢说,我们应该从以前设计过 Forms 应用程序的 UX 角度获得反馈。 它应该像 XamlC 一样选择加入。

虽然不确定名称,但 FlexShell 会更有意义……但我们现在有了 Flexbox(即使我们从未要求过它……对不起,大卫,我忍不住了😄)

另外,这是否意味着主题已经死了? 反正从来没有用过。

@麦凯恩

这当然是我们会使用的东西,因为目前我一直在对我们的 UX 人员说“这是 Xamarin Forms 的一个限制”(就像我在之前的角色中所做的那样)。

好的,但是,修复或改进当前的实现而不是创建一个全新的实现是否更有意义,因为它也会带来错误和限制? 它在那里说:

MaterialShell 在某些方面是一个固执的 API”

说真的,Xamarin Forms 可以朝多少个不同的方向发展? XF 团队几乎无法为至少 Android 和 iOS 修复当前的 XF 实现,现在呢? 修复错误、修复 XAML 预览、性能如何?

有人打开了一张票,建议为跨平台实体和渐变画笔添加简单但非常有用的支持,但@jassmith 的回应是这会有问题。 但是现在这张票提出了同样的事情......那怎么不再有问题了? 去搞清楚

@opcodewriter

是的,我一直在说,在过去的一年里,例如,有导航的怪异阻碍了 Prism 团队,他们从来没有能够解决问题。

我现在只是想提供建设性的反馈,但 Xamarin Forms 正处于它发展的关键时刻,如果它以灵活的方式而不是应用程序范围的方法实现,这个 API 可以解决许多痛点。

@jassmith这是否意味着 XF 将为 Shell 采用 Flutter 方法(使用渲染引擎而不是本机控件)?

伙计们,昨天 Jason 和我自己讨论了如何改进这个规范,我们将做一个大的更新,我们把它分成不同的问题。

我想回应上面的一些观点:请让我们改进我们所拥有的,当然除非你有无限的资源,然后去做吧😉

还有很多事情没有解决:修复 ListView(很难相信这仍然不能正常工作),实现 CheckBox、RadioButton 等控件,实现画笔支持(SolidColorBrush、GradientBrush),基于页面显示弹出窗口的能力或 ContentView、修复错误(请参阅最近报告的关于透明视图的错误)、性能、工具等等......

为什么要开始新的事情????

@TonyHenrique是的,照片会很棒。 不幸的是,我不是艺术家,也不拥有我用于自己参考的图像的权利。 我希望一些设计团队成员有时间帮助我为规范制作合适的图像。

@穆海姆

  • 平板电脑支持。 它旨在确保布局适应平板电脑。 这当然不会涵盖您的内容页面
  • 大多数情况下只是将您的 ContentPages 放在正确的位置并适应新的导航概念。 我不会说这总是微不足道的,但也不应该使人虚弱。
  • 绝对不会删除任何功能。 事实上,我正在努力更新规范以包含一个缺少 MaterialShell 的一些功能的 Shell 基类,但它是 Shell 的特定于平台的 UI 版本。
  • 是的。 添加绘图只是将您获得的渲染器更改为已知如何处理绘图的内容。
  • 是的。 您可以换出在层次结构的任何级别使用的渲染器。 渲染器只是通过在资源字典中使用特殊键设置的模板来更改。 您可以将这些模板更改为您想要的任何内容,也可以通过为它们设置 null 来禁用它们。

@ChaseFlorell不,但如果您想对规范​​附加修正案,我愿意接受建议。 至于 Shell 与 MaterialShell 的事情,我在上面提到过。 第 1 步是确保 MaterialShell 有意义,然后将其分解为基类是第 2 步。

@dylanberry基类不会真的让这变得更容易。 它不像改变DrawingTemplates那么简单。 我打算在平台特定的代码中实现它的 MaterialShell 方面以获得最佳性能。

@RichiCoder1手势将在这里出现,但要点是带有子区域手势的视图将作为 CommandableSpan API 的一部分出现,并且它将被扩展以支持带有手势的绘图。 但是,一般情况下,建议不要使用手势并让本机后端处理输入。 现在这与 MaterialShell 规范无关,属于绘图规范,我很乐意在其中详细介绍。 长和短是 DrawingTemplate 之所以存在的原因是我们可能包含一个 SliderDrawingTemplate,它具有多个绘图,渲染器知道如何从其中组合一个滑块,并允许在本机后端继续处理输入处理。 这并不意味着您将被迫这样做,这只是使渲染器尽可能快的可选操作。

@mackayn Transitions/Segue API 即将推出,应该很快就会出现在这里。 我仍在制定我的一些初始提案命名。 它肯定会分阶段出现,只有页面转换处于第 1 阶段。然而,这将允许您覆盖框架动画。 至于选择加入。 Shell 必须是应用程序的根目录,并且不能嵌套除 TemplatedPage 之外的任何内容。 也就是说,内部控制主题是 100% 由您控制的。 它只不过是打开/关闭新模板的魔法开关,您可以像我们一样控制该开关。 这使您可以在页面、布局甚至控件级别选择加入和退出主题。

@encrypt0r不完全是。 把它想象成一个混合体。 它将允许渲染,但在引擎盖下,它的所有平台特定控件只是以绘图代码为主题。 然而,Skia 有一个可以轻松添加的逃生舱口(尽管我怀疑它是否接近 v1)。

@opcodewriter ListView2(显然它实际上不会被命名)终于在今年的路线图上。 为什么是一个新的 ListView? 好吧,原始 API 导致了几乎无限数量的错误和问题,如果不完全破坏向后兼容性,我们就无法真正有效地修复这些错误和问题。 Cell/ViewCell 和 ItemsView 之类的东西和 TemplatedItemsList 虽然它们在 1.0 中运行良好,但远不能满足现代 API 使用所需的功能。

不幸的是,我想不出在 ListView 类型本身内解决这个问题的任何方法,而且我认为社区也无法不幸地解决这个问题。 现在最好的选择是保持 ListView 原样,然后用更少的开销、更少的簿记、更少的不需要存在的奇怪类型来制作更时尚的东西,并相信目标框架会做他们最擅长的事情。

简单地删除旧的回收策略,这将是我们无法执行的巨大反向兼容破坏性更改,将删除 Xamarin.Forms 代码库的相当大一部分。 ListView2 将通过删除这些旨在成为护栏的项目(或者在 Cell 的情况下,两个不同内部项目的邪恶合并)使您更接近金属,现在只会伤害每个人。

旧的缓存策略会影响当今存在的每个渲染器。 这就是为什么每个渲染器都支持改变其元素的原因。 如果按照我的最佳估计消失,项目中大约 10% 的代码就会消失。 这确实是该项目最大的癌症。

@davidortinau你得到你自己的评论只是因为你有这么多可爱的格式!

如果我使用这种方法在顶层描述我的应用程序,我会得到:

  • 一个应用程序的主题在每个平台上看起来都一样
  • 材料设计(在这种情况下)模式默认开启
  • 通过配置启用的最新导航模式
  • 我不必费力自定义 Entry 或 Button 以在 iOS 和 Android 以及 UWP 上看起来相同?

那是准确的吗? 我应该强调的其他好处?

对,那是正确的。 您可以强调许多其他好处,但是一旦您开始使用它,它们就会变得显而易见。 就像你可以做底部工作表,有一个 FAB,使用 URL 导航(更新仍在进行)等等。

我有 MaterialShell,而不是 App。 我需要学习/采用新的顶级应用程序范式才能从中受益吗?

错误的。 您的应用程序 MainPage 是 MaterialShell。 应用程序仍然是您的应用程序根。

一旦我进入我的应用程序,我就会回到 ContentPage 领域,对吗? 但我所有的按钮和条目都是物质丰富的,而且很漂亮。

除了上面你错的地方,是的,这是正确的。

我是否仍然可以使用 OnPlatform 等来使外观(或行为)在另一个平台上有所不同?

是的。

从现有应用程序到使用这个“shell”,我的迁移路径是什么样的?

看看 Google Play Store repro case,想象一下把你所有的应用程序当前页面放在那里。 这只会替换应用中直接使用 Nav/Tab/MD 页面的区域。 它不会对您的 ContentPages 产生任何影响。

我介绍了新的 MaterialShell,描述了我希望我的应用程序的结构和外观,然后运行它来看看新的优点?

答对了

如果我喜欢 Flyout 或菜单项的外观,但我需要调整它们以匹配我的设计师组合,我有哪些选择?

您完全控制标题,标题如何折叠和隐藏。 您可以完全控制弹出窗口中每个“单元格”(它们不会是单元格)的外观/感觉。 您也可以完全控制其中每个组的标题。 实际上,您可以控制所有内容的“外观”,但是我们仍然需要添加一些额外的位置供您放置额外的内容。

在什么时候我会说“呃,我应该自己完成这一切”并将我拥有的内容移动到标准的 Xamarin.Forms 应用程序结构?

如果 Google Play 商店物理布局弹出窗口看起来与您想要的完全不同。 没有一点不同,完全不同。

如果我必须完全放弃 MaterialShell,我是否会失去所有样式的优点,而我又回到了我开始的地方(就像今天一样),其中一个条目在 iOS、Android 和 UWP 之间看起来完全不同? 我不想。

没有 MaterialShell 只是设置一些默认资源,以便它的子项获取它们。 你将能够自己做到这一点。 无论如何你可能不得不这样做,我们实际上并没有承诺让 MaterialShell 默认这样做。 如果我们确实让它选择加入而不是选择退出,它将是对任何子树的单个 API 调用。

有一个我期待的临界点。 在我使用这种方法快速开始之后,我会遇到一些限制并需要探索我的选择。 它们是什么,在什么时候我最好不使用 MaterialShell?

目的是你最好不要去非壳牌。 您可能不想要Material,但您应该始终想要 Shell(Shell 基类再次出现)。 为什么? shell 的外观/感觉将更加可配置,导航故事将更加统一,您应该对其他页面无法做任何其他页面无法做的事情。

更好的是,目的是确保 Shell 渲染器实际上可以轻松配置和正常运行。 没有神奇的隐藏类,也没有我们难以理解的自定义原生视图子类。 渲染器的每个组件都将尽可能多地组合和交换。 那样的话,如果它不能按你想要的方式工作,你实际上可以修复它......

为什么我们一开始不这样做? 这在早期并不是一个设计目标,然后我们就这样结束了……这足够大、足够新,我们不必随身携带那个错误。

@opcodewriter

说真的,Xamarin Forms 可以朝多少个不同的方向发展? XF 团队几乎无法为至少 Android 和 iOS 修复当前的 XF 实现,现在呢?

修复错误、修复 XAML 预览、性能如何?

^^ 这个

@migueldeicaza

伙计们,昨天 Jason 和我自己讨论了如何改进这个规范,我们将做一个大的更新,我们把它分成不同的问题。

米格尔,这显然将是一项艰巨的工作。 我不能代表所有开发者发言,但我可以告诉你,我的团队想要三样东西:稳定性、性能和灵活性。 我们希望修复错误。 我们希望我们的应用程序运行流畅,我们希望能够实现我们的 UI/UX 设计师给我们的设计,而不必转身说“对不起,这在我们的平台上是不可能的”。 该规范似乎与该目标背道而驰。 这将需要在工作中投入更多资源,这意味着您的资源不会被释放用于稳定性、性能和灵活性方面的工作。

这会是新的默认行为/以 xamarin 形式开发的方式吗? 或者我们是否仍然可以选择使用每个平台特定的外观和感觉来构建我们的应用程序?

@DanielCauser虽然我怀疑从长远来看这可能会成为“默认”方式,但这绝不会取代当前方式。 它将只是一种更加集成和现代的方式,它将提供更多的人目前默认手动构建的 shell。 最重要的是,由于我们将 shell 作为单个控件提供,因此我们可以优化它的绘制和布局方式。 您将不再有 3 个仅用于外壳的绘图通道。

我谨慎地支持这个想法,前提是它提出的改进是通过底层 Xamarin Forms 代码的改进来解决的。 如果这在 Forms 之上增加了更多的复杂性,我不会使用它。
就我的钱而言,我更希望将开发人员资源用于使 Forms 比目前更灵活、更快和更完善。 如果发生这种情况,我可以在这里为自己制作所有建议的新功能。 在这种情况下,DIY 几乎肯定比 Xamarin 提供的通用工具包更适合我和我的客户,无论它有多好。 除了几个值得注意的例外,这个提议并没有解决我目前面临的问题。

@jassmith

  1. 有 500 多个未解决的问题。
  2. Xamarin Forms 已经 3 年了,基本控件和功能仍然存在错误,仍然缺乏重要的功能,性能还没有完全确定(我知道做了一些改进,但在 Android 上的性能明显低于标准)。
  3. Xamarin Forms 开发团队的规模仍然不足。

你为什么要现在开始研究这个全新的功能? 首先关注以上内容不是更有意义吗?

关于您上面与 ListView 相关的评论:我赞赏任何大胆的做法,包括完全重新设计\替换它。 并不是说 Xamarin Forms 中的一切都很棒,不应该触及\更改。

@opcodewriter

1) 是的。 我同意这是一个问题,并将继续成为我个人推动的优先工作项目。

2) Android 上的性能是造成这种情况的部分原因。 这为框架提供了更多的页面转换时间,因此我们可以隐藏诸如 JIT 时间之类的东西。 我们可以更智能地主动加载和保留页面。 XF 团队无法修复的是整体 JIT 时间。 如果您在启用 AOT 且速度更快的 Android 中运行您的应用程序,我无能为力。

3)这里没有参数。

你为什么要现在开始研究这个全新的功能? 首先关注以上内容不是更有意义吗?

这项工作没有安排,我们只是在这里讨论一个规范。 我的管理层会在他们认为适合我的建议时安排它。

关于您上面与 ListView 相关的评论:我赞赏任何大胆的做法,包括完全重新设计\替换它。 并不是说 Xamarin Forms 中的一切都很棒,不应该触及\更改。

ListView 确实是 Xamarin.Forms 的缺陷。 在这 500 个问题中,其中 220 个被标记为错误(也有很多内务或增强问题),25% 以北仅与 ListView 有关。 为了进行比较,与整个 UWP 平台相关的百分比大致相同。 更糟糕的是,Android 中相当多的基本上被描述为在处置后使用渲染器的崩溃者也是 ListView 错误,但是它们不太可能出现在我的搜索中,因为 ListView 将不会出现在搜索查询中的任何地方。

@jassmith除了修复现有问题(除了 ListView,还有其他一些事情仍然不能正常工作),还有一些重要的功能被遗漏了(随机顺序):
- 真正的弹出支持(仍然缺少基本和常见功能)
- 导航返回时取消页面导航(长期未解决的问题)
- 缺少基本控件(没有 CheckBox、RadioButton 等)
- 跨平台绘图(画布控制或其他方式)
- 支持跨平台绘制实体\渐变画笔(SolidColorBrush、GradientBrush)

我希望在使框架真正更丰富的方向上做更多的工作,而不是添加像 CSS 样式或 Flexbox(它们有自己的问题)之类的东西。

@opcodewriter

真正的弹出支持(仍然缺少基本和通用功能)

公平,它似乎从来没有得到足够高的优先级以成为现实。 这实际上在某一点上进展得很顺利。

返回时取消页面导航(长期未解决的问题)

这实际上是 MaterialShell 旨在解决的问题。 这在 NavigationPage 中无法完成是有充分理由的。

缺少基本控件(没有 CheckBox、RadioButton 等)

其中一些是目前正在进行的 F100 计划的一部分。

跨平台绘图(画布控制或其他方式)

这将是 #2452 中指定的姊妹 API

支持跨平台绘制实体\渐变画笔(SolidColorBrush、GradientBrush)

和上面一样的答案。

@jassmith

公平,它似乎从来没有得到足够高的优先级以成为现实。 这实际上在某一点上进展得很顺利。

好的,期待在 2018 年底之前优先考虑它:)

这实际上是 MaterialShell 旨在解决的问题。 这在 NavigationPage 中无法完成是有充分理由的。

您能否提供更多详细信息,为什么在当前实施中无法做到这一点?

其中一些是目前正在进行的 F100 计划的一部分。

我知道了。 手指交叉..

您能否提供更多详细信息,为什么在当前实施中无法做到这一点?

我不会在这里更多地讨论这个,因为我们正在大量偏离轨道,但要点如下:

  • 您无法在 iOS 中被动地取消向后滑动手势。 由于这是人们使用较大的手机导航回来的主要方法,因此这成为一个明显的遗漏。
  • 虽然技术上可以在 iOS 中覆盖此行为,但它需要以一种我们无法确定在新版本的 iOS 出现时实际支持或工作的方式深入了解 UINavigationController 的内部。 简而言之,苹果似乎并不喜欢人们这样做。

关于它如何影响造型,还有一些其他的小问题。 然而,这就是长话短说。 如果您仍然希望讨论此特定功能,我建议您开一个新问题 :)

@jassmith
我认为只处理gestureRecognizerShouldBegin并调用类似OnBackButtonPressed东西就足够了。

总的来说,我真的很喜欢我正在阅读的很多内容,但是这并不像是应该在核心 Xamarin Forms nuget/repo 中完成的事情。

这是一种固执己见的方法,应该建立在 Xamarin Forms 之上,而不是内置于其中。 我认为这是一个单独的库,它使开发人员能够采用不同的方法。 Xamarin Forms 需要公开的部分应该是,并且应该建立在这些位之上。

就像当开发人员决定使用 Xamarin Classic/Native 或 Xamarin Forms 时,我可以看到类似的决定使用 Xamarin Forms 或 Xamarin Forms with a Shell。

Xamarin Forms 应该专注于创建最好的跨平台 UI 框架,而不是试图使平台看起来彼此相似。 今天,Xamarin Forms 在确保平台感觉受到尊重方面做得很好。

我可以看到 Xamarin Forms 存储库中有一个基本 Shell 以及一些有关处理 Shell 的代码,但 Material Shell 似乎与特定设计语言和导航模式的耦合过于紧密,我认为它应该位于 Xamarin Forms 存储库中。

@吉姆森先生
感谢您的反馈意见。 公共 API 表面区域的确切位置尚未确定。 两种方法各有利弊。

规范将更新(希望很快)以同时拥有 Shell 和 MaterialShell 类。 MaterialShell 类将是我们考虑移出核心的部分。 壳牌将是你所描述的。

更新了 Shell 突破和导航规范更新

我真的很喜欢现有的 XF 实现......更强大,更好地使这样的东西作为插件存在,而不是作为 BCL 的一部分。 因此,拥有正确且稳定的强大底层平台将使现有应用程序和任何像这样的新层受益。

期待这东西的进化。

@jassmith @brianlagunas

只是一些观察。

  • BackButtonBehavior,当然应该有一个可见性属性,以防你根本不想要它?
  • materialshell 导航方案就像 Prism,它是否适用于这些现有框架? (棱镜、FreshMVVM、MVVMCross)
  • 你能完全覆盖导航栏中的布局吗? 就目前而言,Forms 在这方面极其有限,最终您会看到笨拙的导航栏,迫使您沿着 customrenderer 路线走下去,因为新版本的 Forms 很可能会破坏您的自定义代码。
  • MasterDetail 没有涉及太多,你能自定义弹出菜单吗?
  • 我们对汉堡包有什么控制权?

我只是想确保解决现有的痛点和限制以及新的新功能。

听起来很棒。

我对 XF 很陌生,但该框架确实有点脆弱,尽管由于您的努力,这当然正在迅速改进。

所以对于它的价值,这是我的意见:-)

高兴Xamarin 目前获得了很多人的喜爱,但我同意

我也喜欢@MisterJimson的想法,即这应该是一个不同的层 - 但你必须对自己的能力和可以支持的框架数量诚实。 我们都倾向于编写令人兴奋的新事物,并避免做出艰难的决定,但我们依靠您为我们的代码开发坚实的基础。

我有足够多的问题让我的代码正常工作而不用担心别人的 :-)

XF 目前处于一个很好的位置,它有可能成为一个真正可靠的工具集。

感谢您为此所做的所有辛勤工作,它确实显示了。

@麦凯恩

BackButtonBehavior,当然应该有一个可见性属性,以防你根本不想要它?

使用 CanExecute 返回 false 设置命令。 我暂时选择不添加辅助方法。

materialshell 导航方案就像 Prism,它是否适用于这些现有框架? (棱镜、FreshMVVM、MVVMCross)

我当然希望如此! 我不能确定,但​​我在想他们和他们所有的麻烦。 例如,这就是为什么所有导航都通过单个事件发生的原因。

你能完全覆盖导航栏中的布局吗? 就目前而言,Forms 在这方面极其有限,最终您会看到笨拙的导航栏,迫使您沿着 customrenderer 路线走下去,因为新版本的 Forms 很可能会破坏您的自定义代码。

这部分比较难。 我想在此处允许尽可能多的可扩展性,但我非常愿意接受有关如何以理智和合理的方式改进这一点的建议。

MasterDetail 没有涉及太多,你能自定义弹出菜单吗?

您可以将标题设置为任意视图,控制用于组标题和项目的模板,还可以添加菜单项。 您可以控制布局的某些方面,但不是 100%。 同样,对您认为自己还需要的其他东西有一些想法会很好。 我清楚地看到需要具有页脚行为属性的页脚。

我们对汉堡包有什么控制权?

BackButtonBehavior 也覆盖了汉堡包。 也许它应该重命名。 我再次对这里的建议持开放态度。 最初我称它为 LeftBarButton,但在 RTL 情况下它不在左边......

@stevehurcombe技术回报持续不断。 这将由一个小得多的团队并行运行。 不幸的是,现实是这个规范的很多内容都以一种奇怪的方式涉及技术回报。 Xamarin.Forms 在其 1.0 版本中产生了大量的 API 债务,并且从那时起就一直背负着这些债务。 XF 中的某些东西很难正确工作,甚至不可能正确工作,这仅仅是由于 API 表达它们的方式。

标签栏和导航栏之间的紧密交互就是一个这样的领域,确保在 MDP 中的标签或项目之间导航是另一个领域。 有很多地方会发生小问题,因为每个元素都无法全面了解应用程序的外壳。

至于工具,有一个完全独立的团队致力于此,他们正在取得巨大进步。 在过去的 6 个月里,内部工具有了很大的改进,我真的很期待你能尝试一下!

@麦凯恩

materialshell 导航方案就像 Prism,它是否适用于这些现有框架? (棱镜、FreshMVVM、MVVMCross)

不要害怕, @jassmith在社区意识到问题出现之前就引起了我的注意......所以我可以有信心地说,这是一个他肯定和我们一样关心的问题。 您可以确定这将是我们希望支持的东西。 这种规模的事情肯定需要大量的跨团队对话,以确保它满足整个 Forms 开发人员的需求,以及满足 MVVM 框架(如 Prism)的需求。

@丹西格尔

很高兴知道两支球队都在对话,这就是我需要知道的一切👍

@jassmith很明显,现在某些东西在 XF 中运行或构建的方式并不是最好的。 因此,与其给猪涂口红(不想在这里粗鲁),为什么不从头重新创建一个新框架或大规模重构现有框架。 我知道,这听起来很可怕,但我很确定绝大多数 Xamarin Forms 开发人员不会介意,我们所有人都会很高兴重构我们的应用程序或其他任何东西,以便我们拥有运行得更好的应用程序。
我见过 PR 因良好的重构而被拒绝,因为“我们不想要这种改变”。 我不确定这个规则是谁制定的,但他应该深呼吸,放松一下,也许重新考虑一下“规则”。
什么是最好的:继续让开发人员使用无法跟上它的框架感到沮丧,或者让开发人员感到沮丧需要做一些重构工作? 只是我的 2 美分...

@opcodewriter你和我都同意,但这是本规范的

只需阅读有关导航的新材料,我就非常喜欢它。 喜欢拥有绑定导航命令的能力,以及围绕 URL 定位导航(就像我假设受 Prism 影响)是聪明的。

具有讽刺意味的是,URI 导航方案是我们当时想要做的事情,并开始推动 Prism 实施,因为我们无法合理地将其纳入框架。 不要拿他们的任何功劳,他们应得的 100% :)

速记的确切语义仍有待研究。

我认为它最终可能会更像:

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

或者

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

因此,扩展可以更精确地了解它们采用的参数。 命名空间主要用于使智能感知易于发现。

@jassmith我真的很喜欢这个 segue 的东西。 请问你打算如何支持推送模式?

我没有所有的细节,但我可以想象 url nav 就像棱镜一样,包裹在标记扩展中。

<!-- 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" />

首先要注意的是,URI 导航仅适用于 Shell。 这是我们可以在没有奇怪边缘情况的情况下始终如一地理解堆栈的唯一地方,我们可以设计导航交互来支持这一概念。

目前我们只支持完整的 URI。 部分更难处理,因为它们是上下文的。

假设当前位置是: app://Shell/Apps/Games/Details ,那么您的 3 个示例将是

特别是这意味着您在一个 Shell 中,其当前 ShellItem 具有 Apps 路由,其当前 ShellTabItem 具有 Games 路由,将 ContentPage 推送到其堆栈中,其中包含 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" />

在外壳 uri 中,第一个位置始终是外壳。 如果不是,则假定为模态推送。 接下来是 ShellTab,然后是 ShellTabItem。 之后是 ShellTabItem 的导航堆栈。 目前我无意将 URI 导航向后移植到所有可能的页面控件。 对于使用 MasterDetailPage 的人来说,这真的很麻烦...

有了路由注册和路由属性,就不需要基于类型的路由了。 我将从规范中删除它。

@jassmith对这个导航的东西给予了更多的思考,我有一些问题

  1. 你怎么能处理CanExecute
  2. 您如何让用户控制(读取阻止)多次点击?
  3. 你如何处理相对导航? IE 你有 3 页深,需要翻到第四页,但堆栈是完全动态的?
  4. Prism 有NavigationParameters奇妙概念,我们不仅可以通过查询字符串/Navigation/MyPage/MyPageDetails?id=33传递基本值,还可以传递复杂对象new NavigationParameters {{nameof(MyObject), MyObject}} 。 你打算支持类似的东西吗?

@ChaseFlorell

1) 带转场? 你目前不能。 绝对需要多考虑。 有一种方法可以创建一个 segue 命令,但它......糟透了。 那会让你处理它,但在这一点上它真的不值得。

2) 在推送完成之前,Segue 将禁用自身。 进一步尝试激活命令 no-op,直到前一个导航任务完成。

3) 您可以使用传统的导航,如带有 segues 的 push/pop。 这些是相对的动作。

4) [QueryParameterAttribute] 可能已经存在也可能不存在,我既不能确认也不能否认。 ;)

我们不太可能添加复杂对象支持。 这个想法是你使用转换器来获取你的简单值并将它们转换为复杂的对象。

从过去的(对于P&P早在CAB-复合UI应用程序块)的经验构建基于URI的应用程序导航,我强烈建议你不要使用System.Uri型,而是只让一切看起来一个URI,但不使用 URI 实现本身。 @pprovost可以证明工作一定在他身上留下了终生的伤疤。 我记得当我们面临互联网 URI限制和错误(即主机名)时遇到了无数问题,我们对应用程序内的东西毫不关心。

我想,部分损害已经造成。

实际上 System.Uri 是支持基于 URI 的导航方案的最佳选择。 虽然 CAB 确实使用了 URI 导航,但它也按照您所说的去做,并通过允许您使用字符串而不是 System.Uri 对象使其“看起来像”一个 URI。 从来不需要主机名。

您要求的是一个非常松散的基于字符串的 API,它可以接受您放入其中的任何字符串语法,这不会产生可预测的结果。 必须有规则才能使基于 URI/字符串的导航方案起作用。

任意 URI 在 XF 中也不起作用。 URL 中的无效字符列表但在文件系统中有效的列表并不小。 这些都是字符串可以工作的情况,而 URI 不会并且需要转义或让用户弄清楚为什么事情不工作(或失败?)并将内容重命名为“URI安全”。

如果您想要更严格的(或更好的语义/解析/验证?),您可以创建自己的抽象,但恕我直言, System.Uri带来了许多并非免费的互联网包袱。 这类似于 Mono/MonoDevelop 创建自己的FilePath来表示路径,路径通常只是字符串。

至少,似乎所有 URI 都被认为是相对的,这简化了事情。 在 CAB 中,我们也使用了带有方案和主机名部分的绝对 uri,这是有问题的。

例如,我更喜欢ResoucePath类的东西,而不是Uri 。 但是在比赛的后期,我很确定它无论如何都完成了。

我不确定您认为文件系统路径与任何事情有关...

您将如何使用 URI 来混淆系统? 它会忽略方案和主机名并开始寻找路由(仅限于 [az])。 如果找不到您输入的任何奇怪字符,它就会停止。 您输入的查询字符串需要是有效的 C# 标识符,否则将无法匹配。 查询字符串数据中的转义数据将不被转义。

@kzu URI 在 XF 中工作得很好,并且比文件系统模式更适合 XF。 实际上,从网站启动您的应用程序时需要 URI。 您应该通过查看 Prism 实现来了解基于 URI 的导航有多强大。 在使用基于 URI 的导航方案使用 Prism 构建的所有应用程序中,从来没有提交与无效字符相关的问题。 我相信您对 XF 平台基于 URI 的架构的担忧不会成为问题。

说得通。 感谢您提供有关 Prism @brianlagunas 的背景信息! 现在我应该仔细阅读规范并提供一些实际有用的反馈;)

非常好的倡议,但我希望通过创建适当的虚拟方法或其他方式为我们的客户做我们的“特殊”事情来考虑可扩展性和定制化。

例如,是否有可能/如何:

  1. 标签可扩展性,例如显示带有图标的徽章。 或者在上面显示一个弹出式抽屉,例如“更多”或“ * ”按钮。
  2. 自定义小吃店(例如,对于您刚刚使用自定义背景/前景色执行的操作的“撤消”按钮)
  3. Android 中的片段推送使用与 Shell 中编程的默认动画不同的动画,例如没有动画以提供尽可能快的导航。

在技​​术说明上:shell 是否会回收页面,以便一旦导航到一个页面两次,本机元素将在其下的不同 vm 中重新使用?

@rogihee

我欢迎您对实施提出反馈意见。 我认为这是疯狂的可扩展性: https :

Android 目前仍在大力开发中,但它使用了相同的方法。

@rogihee至于页面的回收,我正试图找出一种可行的合理方法。 一般来说,它目前没有,因为它需要明确选择加入。

这些“创建*”选项看起来不错。 很高兴看到这方面的迅速进展!

我想知道重用元素是否对性能有任何影响。 就我个人而言,我会优先考虑应用程序的速度和“流畅”感觉,而不是更高的内存/CPU 使用率(尽管最终在某处存在相关性)。 并将 iOS / Android 置于其他任何东西之上:-)。

壳牌非常注重流动性的感知。 它还没有到位,但它正在聚集在一起。

我真的需要让一些早期用户尝试用 shell 做一些疯狂的事情,以确保它可以处理它设计的负载。

@jassmith mig 刚刚在 Build 中提到了 3 分钟的 shell .....

我不是他爸爸

+1

更新了 API 以匹配当前的世界状态,仍然需要更新示例。

添加了一些更新的示例,仍然需要做很多工作来修复其他示例并在使用速记语法时更新路由描述(因为你得到了速记路由!)

天哪,我觉得聚会太晚了。 伟大的写作和讨论。 我浏览了所有内容(在机场很抱歉)并有我自己的建议。 抱歉,如果在其他地方提到了这一点。

@jassmith @migueldeicaza能否请您向导航栏添加行为,以便在 ListView 滚动时可以将其滚动,并在向相反方向滚动时显示。 几乎所有的专业应用程序都会这样做以显示更多的房地产。 这在小型设备上特别有用。

另一个问题是为什么不重命名 XAML 标记以便它们更易于掌握? 也许使用 Tab 而不是 ShellSection? 现在有很多 ShellX 标签。

对于 iOS,我相信有一个属性可以打开/关闭以在导航栏上启用滚动模式。 对于 Android,您需要开始使用新的布局(CoordinatorLayout、AppBarLayout 等)。 XF 的 Android 实现在这方面已经过时了,因为它仍然使用 RelativeLayout 作为主容器。 我认为有一个关于这个特定问题的增强票。 我很想看到 Shell 支持不同的滚动模式。

此外,我们经常必须实现自定义行为以在页面上显示错误/其他类型的弹出窗口。 Shell 应该开箱即用地支持此功能,因此我们不需要求助于 3rd 方插件或创建复杂的 UI 层次结构。

@adrianknight89

能否请您向导航栏添加行为,以便在 ListView 滚动时可以将其滚动,并在向相反方向滚动时显示。 几乎所有的专业应用程序都会这样做以显示更多的房地产。 这在小型设备上特别有用。

这就是我真正想要找出正确方法的事情。 不幸的是,并非所有平台都支持此功能,因此它可能最终会成为特定于平台的交易。 Android 至少是为了支持这一点而构建的,我偶尔会打开它以确保它仍然有效。

另一个问题是为什么不重命名 XAML 标记以便它们更易于掌握? 也许使用 Tab 而不是 ShellSection? 现在有很多 ShellX 标签。

这里的命名真的很难。 ShellTab 对顶部和底部有点混乱。 相反,我选择了更通用的分层名称,但是我不得不承认我对命名不满意。 建议 100% 受欢迎......并不完全期待再次重构他们的名字,但你能做什么......

对于 iOS,我相信有一个属性可以打开/关闭以在导航栏上启用滚动模式。 对于 Android,您需要开始使用新的布局(CoordinatorLayout、AppBarLayout 等)。 XF 的 Android 实现在这方面已经过时了,因为它仍然使用 RelativeLayout 作为主容器。 我认为有一个关于这个特定问题的增强票。 我很想看到 Shell 支持不同的滚动模式。

Shell 使用 CoordinatorLayout + AppBarLayout 并且暂时基本上“禁用”了滚动支持,但是它确实有效。 iOS 滚动关闭也很容易实现。 不幸的是,UWP 的 NavigationView 不支持此功能。

此外,我们经常必须实现自定义行为以在页面上显示错误/其他类型的弹出窗口。 Shell 应该开箱即用地支持此功能,因此我们不需要求助于 3rd 方插件或创建复杂的 UI 层次结构。

例子,我需要例子:)

@jassmith

我正在使用 James Montemagno 的连接插件来监听数据连接状态的变化。 当 Internet 连接断开时,最好显示一条通知,该通知在 Internet 重新联机之前滑动/淡入淡出或保持静止。

在 Instagram 上,此通知位于导航栏正下方。 在 Tumblr 上,它就在底部导航栏的正上方。 在 YouTube 上,奇怪的是它位于底部导航栏下方。 也许这样的东西可以成为壳牌的一部分?

据我所知,建议的 Popup 控件覆盖现有窗口,尽管它可以轻而易举地关闭。 我刚刚提到的通知和可能的其他类型的通知不需要覆盖它们的父窗口(即父视觉树仍然响应手势),所以我不确定 Popup 是否合适。

Shell 可以为我们提供一个属性来定义此视图(称为 Notification[View])的外观以及它的位置和进入/退出动画行为。 所以本质上是一个内置于 Shell、INavigation 或其他东西的跨平台 toast/snackbar 实现。 这不会被迫在每个平台上看起来都是原生的,但在所有平台上都是一样的。

d1c014c0-fc7b-4788-9689-1948a7294426

bc91d3ca-b95f-4485-a917-db6ab47510c1

关于稳定性、灵活性等方面的争论,在不摆脱来自 1.0 的过时架构的情况下,我认为实现这些目标是不可行的。 我非常赞成 ListView2。

@jassmith

  • 你有新 ListView 的增强票吗?
  • 你认为 v1.0 什么时候出? 我们有机会在 EOY 看到它吗?

此外,我对团队规模过小也有同样的担忧。 事实上,我过去曾经提出过这个问题。 我希望团队在未来能够变得更大。 🙏 @davidortinau @migueldeicaza

@jassmith我相信一段时间以来,如果我们为 App 类提供了一个渲染器,我们可以做很多目前需要 3rd 方黑客才能实现的事情。 例如,RgPopups 插件抓取应用程序的主视图并将渲染视图注入其中以提供全屏弹出外观。 目前,使用“纯”Xamarin Forms 无法实现这一点。 但是,如果 App 有一个渲染器,我们可以自己做。

我完全赞成将这些类型的 Toast 通知添加到 Shell,只是想弄清楚应该如何完成。

你能不能让你可以在应用程序中任意放置页面? 这在平板电脑/台式机/笔记本电脑(大屏幕设备)上尤其重要,您希望同时在屏幕上显示多个页面,并且不一定要使用拆分视图(主详细信息页面)来组织它。 示例,参见谷歌地图:

image

请注意内容如何“浮动”在地图顶部(无拆分视图)。 如果你想在浮动区域内使用选项卡或导航之类的东西,那么你不能用 Xamarin Forms 完成这类事情,开箱即用,因为页面的层次结构极其有限(不能嵌套页面视图内)。 我们实际上开发了我们自己的自定义视图,它提供了类似于 NavigationPage 的功能,但它是一个视图,这样我们就可以完成这种布局,但需要做很多工作/很难做到。

应该可以将内容(包括页面)放在应用程序中您想要的任何位置。

你能不能让你可以在应用程序中任意放置页面?

我有点好奇@jsiemens,因为这个视图在手机上可能看起来不正确,但在台式机和平板电脑上看起来很棒。 你能扩展一下你可能期望它如何工作吗? 最终,我很想说您正在将 Region 概念从 Wpf 带入 Forms。 我的下意识反应是,虽然我喜欢这个概念,但我们冒着让已经很复杂的导航 API 需要博士学位或至少是天才级 IQ 的风险,这对用户采用来说不是最好的事情。

@dansiegel至少就我个人而言,当低于某个视口阈值(就像 GMaps 当前所做的那样)时,我可能会使用 VSM 或某些等效工具来移动和压缩底部的滚动视图。 很想知道导航和状态管理如何为此工作。

导航:如果您从用户旅程的角度出发,然后查看用户期望它如何工作,我相信这不是一个不可逾越的问题。 例如,导航需要响应手机的全屏特性与较大屏幕上的较小视图。

用户将“看到”平板电脑和较小的视图作为单个导航里程碑。 在一个小屏幕上可能有两个里程碑。 不知何故,导航必须是响应式的。

作为开发人员,我们肯定必须处理这种响应性质,因为它是一个上下文事物。 我们不能依赖框架来为我们处理这个问题,但框架需要支持它。

@jsiemens @dansiegel我目前处理这个ControlTemplate s。 我将“页面”类型的内容构建为ContentView并将它们托管在适合平台的ContentPage (在NavigationPage )中。 使用ControlTemplates意味着我可以有多个绑定ContentViews (通常在Grid以便我可以覆盖内容),根据ControlTemplate中的可绑定属性打开/关闭DynamicResource s)。 最终结果有点像网站上的 CSS 面板,其中所有内容都在页面中,但并非所有内容始终可见。 ControlTemplate s 在这方面很神奇,我希望它们的功能能够保留在 Shell 中。

@dansiegel我会根据应用程序是在手机还是平板电脑/笔记本电脑/台式机上运行,​​简单地对其进行编码以加载不同的外壳。

@jsiemens很好,我的评论只是为了激发进一步的对话和批判性思维,以进一步完善您的想法。 在某些方面,我几乎可以说,鉴于您在这里的概念,每个页面本质上都可以是一个多页面,其中一个页面可以附加到给定的控件,并且更多地被视为另一个视图与普通导航。

@dansiegel是的,我认为这就是我所追求的是能够将页面添加到应用程序中的任何地方。 奇怪的是,当底层平台没有时,Xamarin Forms 强加了这个限制(例如,iOS 只是一个视图的树层次结构 - 您可以将 NavigationController 的视图添加到应用程序中的任何地方)。 此外,我的评论旨在表明 Shell 规范没有必要涵盖这一点 - 我认为“响应式”布局不需要成为问题。 我认为只要可以构建布局,我们就可以根据外形因素有条件地加载外壳,这就足够了。

我想它并不完全是这个规范的主题,但我在这里提到它是因为我们正在讨论如何构建复杂的布局(例如@MelbourneDeveloper的第三个优先级 - 灵活性),而且这肯定是一个最重要的布局请注意我和我的团队(我们正在构建一个地图应用程序,我们希望能够在地图顶部浮动内容面板,其中可以包含“仅限页面”的内容,如导航页面和选项卡)。

我不知道如何使用 shell 解决这个问题,但我对 shell 的最初反应是它似乎没有做任何我已经做不到的事情。 我通常觉得 Xamarin Forms 团队一直在构建功能,让我可以做我已经可以做的事情,但只是以不同的方式(例如,CSS、视觉状态管理器,以及现在的绘图和外壳规范)。 所以这对我来说没有多大价值。 我宁愿拥有新功能,让我可以做我以前做不到的事情(在自定义控件和/或渲染器之外)。 如果 shell 是实现这一目标的答案,因为它的语法更优雅,那么我完全支持它,但最终我希望它比当前的页面/视图层次结构更强大和更具表现力,因为它确实带来了价值。

如果布局中的所有子视图都可以在不使用本机小部件的情况下呈现,您能否与为每个 xamarin 视图创建本机视图分离? 一种自动混合 flutter/xamarin 方法,其中 XF 视图组被渲染到单个表面,然后直接输出到一个本机视图上。 避免 Android 视图创建/布局 c# -> java 互操作成本会很有用。

进行中!!

@jassmith shell 完成后,一起绘制是否有效?

shell 会支持 macos 和 wpf 吗?

@juepiezhongren最初的目标是 iOS 和 Android。 之后将优先考虑其他平台。

绘图目前尚未开发。 在其当前规范中,它对壳牌有效。 就像今天一样,您可以在 Xamarin.Forms 中使用 SkiaSharp 和基于 Skia 的控件。

我们正在研究其他原生策略,以支持材料和其他设计风格的一致设计。

@davidortinau shell 是否使 RTL 支持更好?

用什么方式更好? 您今天从 RTL 支持中遗漏了什么? 我们应该到处解决它。

老实说,我有一段时间没有做 XF 开发,但大部分限制都知道:看看#1222 和 #2448

也许 shell 可以帮助解决这些一般限制:

  • NavigationPage 按钮位置、工具栏项位置和过渡动画当前由设备区域设置控制,而不是 FlowDirection 设置。
  • FlowDirection 的全局应用程序设置

以及其他一些特定于平台的限制

Xamarin.Forms 最重要的特性。 它本来应该是这样建造的。

不画图,xf还欠缺不少

@juepiezhongren

只需使用 Skiasharp

@mackayn我经常用它
https://github.com/xamarin/Xamarin.Forms/issues/1789
通用外观是必须的

adam去了flutter,这对xf来说真的是一个悲哀的信号,xamarin原本可以轻松获得更好的声誉

xamarin.native 对于 xf 来说比任何其他跨平台解决方案都要可靠得多,无论是 react native 还是 flutter。 作为dotnet爱好者,xf的现状总让我有些失望。

@juepiezhongren

这个讨论毫无意义,如果它不能满足你的需求,使用 Flutter,它允许我们跨多个平台交付应用程序(iOS 和 Android 仅使用 Flutter 等),这些更改将使一致的外观和感觉更容易实现。

简单的小抱怨,就这么多。 还是壳万岁!

我同意将 Skia 更多地融入 Forms api 会更好(就像 Telerik 所做的那样)。 我同意。

我很高兴他们在 Shell & CollectionView 上投入了大量精力。

嗨,请大家说,对于从右到左的语言,我如何在右侧使用 should flayout。

你好,

我喜欢这个想法,但我只有一些小的投入。
我想我有点晚了,但我认为命名有点混乱。

  1. Item、Section 和 Content 都是非常通用的名称。 目前还不清楚它们之间的关系。 是内容=> 部分=> 项目或部分=> 内容=> 项目,还是项目=> 部分=> 内容。
    因此,我们可以通过查找更具体的名称来详细说明不同的“事物”是什么。

  2. 这使我进入下一个输入。 我们有一个 Shell 作为所有内部项目的容器。 所以我们不能在里面直接使用像“Item”这样的直接名称而不是“ShellItem”。 对我来说,调用所有“事物”Shelltem、ShellSection 等似乎有点不必要,但没关系。 这是有争议的。

哎哟

它还会在2018年发布吗?

我们现在有一个预览版! 查看https://blog.xamarin.com/connect-2018-xamarin-announcements/以获得一些很棒的示例。

我们真的需要Android 9吗? 这似乎有点限制。

这一切听起来都不错,但似乎完全基于 UI 交互。
我想我会在尝试时发现,但我最初关心的是如何从业务逻辑或代码驱动导航,例如从触发页面更改的蓝牙连接设备接收到的消息,同时保持关注点的适当分离?

@hassanrahimi

嗨,请大家说,对于从右到左的语言,我如何在右侧使用 should flayout。

虽然支持 RTL,但弹出菜单仍显示在左侧。 这是当前的限制。

是否可以自定义底部标签栏 ui?

是否可以向外壳添加控件,在外壳内导航时不会重新加载? 例如FAB..

@stfnilsson底部

计划为 MaterialShell 添加像 FAB 一样的全局控件。 除了 FAB 之外,您能否提供可以从中受益的其他场景?

第一:我以前使用过自己的外壳,现在我可以很容易地用你的外壳替换我自己的外壳,而且效果要好得多。 我很喜欢。

可能是我自定义的案例方式,与 shell 无关,但是:

案例一:
如果我想创建一个带有非常自定义菜单的应用程序,应用程序的每个角落都有一个菜单按钮,我如何添加按钮使其成为外壳的一部分(如叠加层或广告牌)。 不希望每次导航时都重新渲染。

案例二:
我想使用外壳但想自定义底部标签栏,因此中间按钮更高(称为中心凸起按钮)。 我应该使用渲染器并自定义底部导航视图吗?

你认为我应该在这种特殊情况下使用 shell 吗?

当然,我考虑在每个平台上都这样做,但菜单在所有平台上看起来都应该一样,所以想共享代码..

这是我的反馈。 我做这个测试( 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>

当我们点击汉堡菜单时,一切正常。 但是,如果我们转到Test菜单并来回点击HomeNotifications并在RecentSettings ,页面将分别打开。 但是,当我们再次点击汉堡菜单时,应用程序崩溃了。

image

我们如何使用GroupHeaderTemplate

许多用户很清楚,Xamarin Forms 无法以其当前的大小和复杂性进行维护,因此任何新事物都应该降低复杂性而不是增加复杂性。

@jassmith目的是你最好不要去非壳牌。 ... 目的是确保 Shell 渲染器实际上可以轻松配置和正常运行。

如果 Shell 完成,将来可以折旧什么,完成后 Xamarin Forms 的整体复杂性会降低吗? 除了 ContentPage 之外的所有其他页面都会折旧吗?

策略应该是尽可能多地从回购中获得收益。 核心 repo 的稳定性和可维护性是最重要的。

此外,如果有一个原因,Shell 不被称为 ShellPage? 其他 Page 类的名称以“Page”结尾。

目前壳牌的广告(在 https://blog.xamarin.com/xamarin-forms-4-0-preview/ 中)并不乐观。

  1. 一种表达应用程序架构高级别的简化方式

这使 Xamarin 超出了它的真正目的。 应用程序架构不需要 Xamarin。 这应该仅与布局有关。

  1. 适合您的目标移动平台的常见 UI 导航模式的层次结构

我希望“移动”在这里是印刷错误,因为 Xamarin.Forms 也涵盖桌面。

  1. 强大的导航服务

Xamarin.Forms 不需要导航。 如果当前的导航不起作用,则可以对其进行折旧,因为有许多不需要内置任何内容的好导航方法。

@charlesroddie ,感谢您的反馈。

听起来壳牌此时可能不适合您,但没关系。 如果 Shell 不能为您的应用程序提供价值,则您不需要使用它。 也就是说,Shell 规范主要是根据开发人员的反馈信息提供的,为我们的开发人员社区提供服务是我们目标的核心。

在今天的 Xamarin.Forms 中,你已经使用 TabbedPage、MasterDetailPage、选项卡和菜单项以及不同的组合描述了你的应用程序体系结构、内容层次结构。 这就是我在这里所说的“架构”的意思。 Shell 简化并替换了这些模式(如果您选择使用 Shell)。

“移动”不是印刷错误,而且是非常刻意使用的。 Shell 面向 iOS 和 Android。 如果您的目标是桌面,则不会使用 Shell。 我听说贡献者对向桌面后端添加 Shell 支持很感兴趣,这些 PR 会很受欢迎。 我相信 Shell 非常适合将应用程序带到任何平台,并且灵活(有弹性)以适应甚至激进的 UI 模式变化(谁知道未来的界面会采用什么)。 今天的试验场是 iOS 和 Android。

当我们与开发人员讨论 Shell 时,我惊讶地发现 Shell 导航在他们看重的功能列表中名列前茅。 路由、深度链接、中断导航的能力、即时描述返回堆栈、传递数据和页面延迟加载对于解决他们今天遇到的问题的开发人员来说是非常引人注目的属性。

如果你的目标是桌面,你不会使用 Shell...我相信 Shell 非常适合将应用程序带到任何平台

我只是不希望 Xamarin 在其自身的重量下崩溃。 在 Shell 到达所有平台之前,您会遇到维护问题,因为它是一个添加,而不是其他页面的替代品。 对于桌面开发人员来说,您还有一个消息传递问题,因为许多人显然希望采用跨平台框架。

Xamarin 显示了很多功能蠕变,例如 css。 这可能会威胁到整个项目,我希望组织中的一些决策者理解这一点。

我只是不希望 Xamarin 在其自身的重量下崩溃。 在 Shell 到达所有平台之前,您会遇到维护问题,因为它是一个添加,而不是其他页面的替代品。 对于桌面开发人员来说,您还有一个消息传递问题,因为许多人显然希望采用跨平台框架。

Xamarin 显示了很多功能蠕变,例如 css。 这可能会威胁到整个项目,我希望组织中的一些决策者理解这一点。

我同意。 如果桌面 ​​(UWP) 不支持某项功能,那么它对我们毫无用处。 我也同意 CSS - 它似乎增加了很多复杂性,以及一个功能的维护开销,它不允许我做任何我以前无法做的事情。 我们最需要的只是更多的控件——适用于所有平台,以及现有控件的更多功能。 Shell 仍然具有与 Page 基础结构相同的限制,即您需要完全采用它或根本无法使用它,并且它只能存在于应用程序的根级别。 不仅如此,现在你有两种方法可以做同样的事情,而且很复杂和令人困惑。 所以如果我只想在不使用 shell 的情况下有一个弹出菜单,我不能这样做。 而且外壳项目映射到的控件数量极其有限——选项卡、导航页面和弹出按钮对我们来说还不够。 如果 Xamarin Forms 能够提供像 UWP 这样的框架所具有的控件的广度,作为一组控件公开,就像在 UWP 中一样,并且没有无用的膨胀(例如 css),那么我会很高兴。

我认为你们提出了一些有效的观点,但作为一个维护 UWP/iOS/Android 应用程序的人,当我得知 Shell 不支持 UWP 时有点失望,未来只有一个“可能”。 然后我意识到我错过了壳牌的重点。 对于某人来说,这是为两个主要移动平台构建应用程序的一种非常简单的方法。 作为企业开发人员...我需要 UWP,我等到有 UWP 支持甚至考虑 XF...但我怀疑很多开发人员不需要它...我还需要更复杂的导航方式,等等壳牌提供。

但我也记得我花了很多时间尝试开始使用导航和页面......这可能需要一些时间来弄清楚。 但我也在制作一个非常复杂的业务应用程序,有很多简单的应用程序不需要那么复杂。 XF 需要进化以完成对抗 Flutter 之类的东西。它还需要不断让新开发人员采用它。 在我看来,使用该平台将有助于保护维护平台所需的资源。

我还有几个未来的项目,我不需要 UWP,我期待在它们上使用 Shell,因为我认为这会让我更快地制作它们。

我只在 2.3 版本左右才使用 XF,虽然肯定还有更多工作要做……现在存在的平台已经大大稳定了……至少对我来说……所以我不关心额外的维护,从历史上看,XF 团队非常关注维护负担……所以我相信他们已经控制住了。

感谢您对平台的大力补充!

添加新的做事方式会使新开发人员感到困惑,直到旧方式贬值并删除旧文档。

Flutter 要简单得多。 没有标记语言,一切都在代码中。 Xamarin 不会通过变得更加复杂和错误来竞争。 它将通过比 Flutter(更多平台)做更多的事情来竞争,并且具有相同的重点。

到了我们需要 Xamarin.Core 的地步,不包括 XAML 或 CSS 或属性绑定,不包括除基类之外的 Pages 或 Shell,重点是此 Core 的性能和稳定性。 如果某些开发人员以接受当前的错误率为代价想要这些功能,他们可以使用 Xamarin.Extensions 来实现所有这些功能。

添加新的做事方式会使新开发人员感到困惑,直到旧方式贬值并删除旧文档。

Flutter 要简单得多。 没有标记语言,一切都在代码中。 Xamarin 不会通过变得更加复杂和错误来竞争。 它将通过比 Flutter(更多平台)做更多的事情来竞争,并且具有相同的重点。

到了我们需要 Xamarin.Core 的地步,不包括 XAML 或 CSS 或属性绑定,不包括除基类之外的 Pages 或 Shell,重点是此 Core 的性能和稳定性。 如果某些开发人员以接受当前的错误率为代价想要这些功能,他们可以使用 Xamarin.Extensions 来实现所有这些功能。

@charlesroddie他们在上面所做的
如果 Xamarin.Forms 无法使用编码的 UI,我不会使用它 - 句号!

总的来说,Re Flutter - 它非常好,但问题在于它只有 iOS 和 Android - 这对我也不起作用,因为我需要针对 macOS、Windows 7/8.1 和 Linux。 没有什么比 Xamarin.Forms 更胜一筹了!

我可以将自定义视图设置为母版页吗,包含非常重要的事情,我们不会只喜欢 MenuItem 或页面

Xamarin Mac 和 uwp 支持吗?

你将如何进入导航过程? 我想你知道这一点,但如果你以 Prism 为例,视图模型是由 DI 容器创建的,并自动设置为请求页面的 BindingContext。

您还可以为视图模型实现INavigatedAware并处理特定用例,例如加载数据、启用/禁用服务等。

我想添加类似的东西,所以我的第一个猜测是OnNavigatingOnNavigated Shell 事件,但是CurrentTarget不公开 ShellItem 所以这是不可能的按约定设置 BindingContext 或触发视图模型事件?

对此有何建议?

编辑:由#5166 跟踪。

对于此外壳中的图标,是否可以使用“图标字体”而不是图片? 图片在运行时很难改变颜色,并且在不同平台上针对不同分辨率管理它们也很困难。 我可以建议使用由 SkiaSharp 库渲染的 Material Design 字体制作图标类吗? 该类相对容易,并且可以制作大量图标以供在 shell 上使用。

@vincentwx我同意。 图标字体更容易使用,也很熟悉。

@vincentwx @stevehurcombe绝对是。 我现在正在一个应用程序中这样做:

<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>

我用它来制作所有字形的静态类: https :

iOS 颜色有一个需要修复的错误。 第5071章

Xamarin Mac 和 uwp 支持吗?

目前不是@mdonogma。 我们正在收集支持其他平台的兴趣/需求,但目前这不在我们的路线图上。

@davidortinau感谢您提供代码和链接。

在 Android 8.0 中,我无法在 Shell 内容中托管的WebView元素中滚动网页。 但它在没有 Xamarin Shell 的情况下工作正常。

Xamarin 表单 4.0.0.135214-pre4

是否有一种简单的方法可以更改底部选项卡和标题视图的 FontFamily?

@varyamereon我昨天做了。 扩展 Shell 以能够设置 FontFamily。
我将很快在 GitHub 上发布我的扩展 Shell,但是:

创建自定义外壳:

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

然后创建一个 Shell 自定义渲染器:

[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
            };
        }

然后:

 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()
{
{

然后设置字体系列:_(不要经常这样做)_

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

任何通过支持从下面(底部)弹出窗口扩展了 Shell 的人?

我已经将很多代码从我自己的旧 Shell 移到了新 Shell(当然是组合),我真的很喜欢它。 我什至将它用于一个应用程序,该应用程序将发布给我 :-)(我什至调试 Xamarin 代码)

是否支持将列表绑定到 Shell.MenuItems? 或者我应该使用 BindableLayout 吗? 有时我需要从数据库加载一个列表并将它们用作菜单。 它们具有相同的视图,但根据所选菜单加载不同的数据。

有什么办法可以在使用 shell 时更改 Android 中的 OffscreenPageLimit 吗? 不幸的是,这对我的应用程序非常重要,并且阻碍了我继续使用 Shell。

谢谢!

几个功能要求:

  1. 在外壳级别,为所有页面标题设置 FontFamily。
    例如

  2. 在外壳级别,为所有页面标题/导航栏等设置标题/导航背景图像。
    例如

GroupBehavior 在 pre4 中对我不起作用:

<ShellItem GroupBehavior="ShowTabs" FlyoutIcon="stuff.png" Title="Discussion">...
结果是:

xxx/Shell/Shell.xaml(14,14):错误:位置 108:14。 找不到“GroupBehavior”的属性、可绑定属性或事件,或者值和属性之间的类型不匹配。

和 GroupHeaderTemplate 似乎没有做任何事情,但是,不确定它是如何使用或启用的。

我正在尝试添加/删除 MenuItems,它通过 MenuItems.Add(item) 成功添加了项目,但是,再次显示浮出控件时没有显示任何结果。 这是这样做的正确方法吗?

我没有看到任何关于操作 MenuItems 的提及,但是,Shell 对我来说几乎没用(我正在考虑很多其他人,包括上面的@puppetSpace ),除非可以根据您的业务逻辑动态维护这些项目。

我同意 dbwelch 的观点,即能够以编程方式更改 cs 文件中的 shell 非常重要。 不仅适用于菜单项,还适用于 ShellItems 和 ShellSections。

当我打开 Flyout 并添加菜单项时,我会在 Android 中得到一个汉堡包菜单,而在 iOS 中,如果我点击那个位置它可以工作,但是没有图标。 有任何想法吗?

@KyleTraynor在某处有一个悬而未决的问题。 您必须手动将 3bar.png 和[email protected]图像复制到您的 iOS 资源文件夹,并确保它们作为捆绑项目包含在项目中。

我在来源中找到的图像附后:
3bar 2x
3bar

@melucas谢谢你的帮助! 我快疯了试图解决这个问题。 效果很好。

你知道如何在使用 Shell 时为 Android 设置 OffscreenPageLimit 吗?

我的顶部标签页由 1 个 ShellSection 中的 4 个 ShellContents 组成,它在 iOS 上运行良好,但在 android 上,页面在我不想要的页面之间交换时会重新加载。 通常使用我自己的标签页,我可以设置 OffscreenPageLimit 来解决这个问题,但是我找不到用 Shell 来做的方法。

@davidortinau我们可以选择在页面标题、底部和顶部选项卡上设置字体系列吗? 在每个项目中,我都必须为 ios 和 android 创建自定义渲染器以更改字体。

因此,鉴于我关于能够实际更改弹出 Shell 中的项目的帖子没有回应,也许此功能不在范围内,或者可能希望被视为错误?

不确定一个严肃的应用程序如何在没有此功能的情况下使用此 Shell。 只有非常简单的应用程序不需要能够根据 a) 用户的上下文(即已验证/未验证)或 b) 应用程序的不同状态添加/更改/删除/禁用其菜单上的项目需要它。

只是好奇@jassmith ,创建规范的人是在这个论坛中输入的还是只是为了开发人员的反馈?

顺便说一句,除了这一主要项目,我已经将 Shell 实现到我的一个应用程序代码中,并且运行良好,谢谢! 但是,遗憾的是,如果 Shell 没有运行/实现此功能,则必须将其拉出并实现我自己的弹出窗口。

@dbwelch ,有几件事。
你在规范上发帖,所以你可能不会像你写的打开一个新问题那样得到回应。 此外,Jason 不再从事 Forms 的工作,所以叫他出来也没什么意义。

底线,提出问题

@dbwelch @ChaseFlorell我在这里打开了一个问题: https :

@davidortinau我们可以选择在页面标题、底部和顶部选项卡上设置字体系列吗? 在每个项目中,我都必须为 ios 和 android 创建自定义渲染器以更改字体。

@jamiewest提交功能请求! 谢谢! 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

UseSwipeGesture 功能可以实现吗?
看起来现在 ShellItem 类没有可操作的 ShellAppearance 属性。
但是现在在 Android 中,Shell 的 Tabs 不像 TabPage(TabPage 可以默认滑动。)

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

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

@juepiezhongren嗨,你可以加入这个qq群和我聊天313308215

我们会在 RTM 上看到对 UWP 的 Shell 和视觉支持吗?

我欢迎这个想法——不管它有多难,因为使用导航页面、主从页面等感觉很复杂。 也许这是因为我来自网络背景(没有太多使用原生 API)。 自定义导航栏、页面标题、后退按钮、工具栏项、页眉和页脚(ListView)等在这里浮现。

我想我所要求的是像 *Shell 这样的新功能在发货时考虑了自定义和可扩展性。 很少有我们不需要制作一系列渲染器、行为、触发器等来执行看似简单的事情的情况。

无论你们想出什么,请尽你所能,让我们更轻松地使我们的 Xamarin.Forms 应用程序看起来与其他本机应用程序一样好! 听起来这个功能将为我们提供一个更好的启动板,用于外观现代的 XForms 应用程序!

是否有可用的源代码来查看此 Shell 的工作方式,而不必猜测规范? 例如,使用什么样式为汉堡包图标着色(如果可用)。 抱歉,C#/Xamarin 的新手,但是,如果代码可以在某处查看,将会有很大帮助。

@dbwelch您可以直接在 GitHub 上浏览源代码。 点击“T”并键入 Shell 以查看关联的类。 但是,如果您不熟悉 C#/Xamarin,这可能不是最好的起点。 我建议查看我的一些示例,直到我们获得更多文档:

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

文档: https : =android
MSDN 文章: https :
博客: https :

@davidortinau谢谢,但是,我认为这只是可用的已发布代码,Shell 代码在哪里? 我已经在分支下寻找 4.0、Shell 和其他版本,但是,它在躲着我! 谢谢!

@pauldipietro谢谢,现在看看。 @davidortinau我实际上已经在所有链接上花费了大量时间(除了我刚刚下载的 LittleThings),但是,只是不知道如何更改像汉堡包图标颜色这样简单的东西。 它在我的应用程序中显示为紫色,但是,我没有在任何地方定义紫色(我可以看到)。 有点令人沮丧;-)。

更新:我刚刚发现了这个问题,当然,FinishedLaunching 中存在一些令人讨厌的代码来添加 TintColor。 哦!

感谢先生们,感谢您的帮助!

我在弹出面板中显示了一些项目,这很好。 但是,目前已经有办法隐藏/不显示 Shell 项目(不是项目内容)。 例如,我有一个 ContentPage,我只想在 Shell 中使用导航。

<local:DetailPage />

似乎总是在弹出面板/列表中添加项目。 如果没有标题,那么它将具有项目的空堆栈/占位符。 我尝试了很多方法来隐藏该项目仍然没有运气。 可能有人可以提供帮助,或者该功能尚不可用。

前言:我是atm新手。 努力不成为。

@davidortinau所以,我一直在尝试学习这个 Shell 功能,以将导航等添加到我们公司的第一个 Xamarin.Forms 项目中(哇!),我一直在试图弄清楚是否有可能通过 1或通过新的路由功能从 ShellItem 到应用程序的其他部分的更多参数。 这是一回事吗? 还是我们必须坚持使用 MenuItem 集合中的 MenuItem 来代替命令? 如果我们必须使用 MenuItem 从 Flyout 级别传递 1 个或多个值,似乎我们不能再使用 Shell 层次结构来构建我们的应用程序,因为我们使用的是 MenuItems? 在使用带有命令参数的 MenuItems 时,我们不会失去它吗?

有没有人可以插嘴? 如果是这样,我将不胜感激。 基本上会喜欢使用 Shell,但仍然能够标记用户在单击时选择的 ShellItem 以将其传递到 ContentTemplate 页面或任何合适的内容,因为许多 ShellItem 将导航到类似的中间页面以创建 OrderType和 OrderDepartment 下拉选择,然后转到带有正确类型和部门的适当数据的主订单屏幕。

另外,如果这是错误的地方,我深表歉意。 如果是这样,请指出我在正确的地方。 谢谢!

更新:
也许我现在只使用 MenuItems 并将命令参数传递给 ShellViewModel 以使用目标页面的正确值导航。 现在我想起来了,我真的不需要从那些推送到 ContentTemplate 页面的 MenuItem 导航到选项卡式结构。

我还想知道我们是否可以定义 MenuItems 在 Flyout 中的位置,这样 ShellItems 就不会全部弹出顶部; 如果有一天我们不必将 MenuItems 定义为集合的一部分,以便它们可以与 ShellItems 混合,例如:
MenuItem
ShellItem
ShellItem
MenuItem
ShellItem
MenuItem
...
那,或者只是让 ShellItems 能够在某个时候传递参数,如果他们还不能。

我和@anthcool 在一起,发现这是一个非常重要的功能。 我无法找到一种方法来做到这一点,不得不停止使用 Shell。 只需要能够将某些内容传递给内容页面即可知道点击了哪些内容。

@anthcool只是像我目前所做的那样试图提供帮助并在这里提出一些建议。 创建一个导航参数类,它有一个readonly Stack<NavigationParameter>作为堆栈列表,即

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

导航参数是:

public class NavigationParameter : NameValueCollection { }

您可以在导航时在推送之前添加参数,例如:

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

一旦你在其他页面,只是皮克流行的价值和检查的关键。
类似上面的东西。 希望有帮助。

@anthcool只是像我目前所做的那样试图提供帮助并在这里提出一些建议。 创建一个导航参数类,它有一个readonly Stack<NavigationParameter>作为堆栈列表,即

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

导航参数是:

public class NavigationParameter : NameValueCollection { }

您可以在导航时在推送之前添加参数,例如:

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

一旦你在其他页面,只是皮克流行的价值和检查的关键。
类似上面的东西。 希望有帮助。

感谢@rizamarhaban 的想法! 真的很感谢你在这方面发表意见。 谢谢! 我很快就会在这里查看。 再次,欣赏!

非常失望学习Shell和Visual不支持UWP。

这个规范真的完成了吗?
为什么仅仅因为现在有一个 Tizen 实现就关闭它?
我的印象是导航功能仍在审查中。

仍然没有 UWP 支持。 我对 Xamarin 的最大失望。

@weitzhandler请给我发电子邮件 paul。 如果您想讨论此问题和 UWP,请使用[email protected] 。 我们并未主动忽略该平台,但 Android 和 iOS 正在接受初步实施,并且正在积极进行对 Shell 对 UWP 支持的调查。

@mrlacey Nah,还

对于所有要求 UWP 支持的人,我尝试了一下: https :

有没有办法在内容页面上实现导航栏模板?
指定 NavigationPage.TitleView 不像以前那样适用。
回购参考:
https://github.com/InquisitorJax/Xamarin-Forms-Shell

编辑:
墨菲再次罢工 - 只需使用 Shell.TitleView 而不是 NavigationPage.TitleView :)

你好,
在我的新项目中,我使用了 Shell 和 CollectionView,我不得不说这很棒!
一个关于壳牌的问题

  • 有一种方法可以添加固定的底部项目(例如,用于用户注销的按钮)

我看到可以添加固定页眉(FlyoutHeader 和 FlyoutHeaderBehavior),但我找不到有关底部页脚的任何信息
谢谢!

你好,
我还有一个关于 RegisterRoute 的问题。
我的应用比较大,有相当多的页面,大约30...
真的是为每个人添加 RegisterRoute 的正确方法吗?
Routing.RegisterRoute("blabla", typeof(BlaBlaPage)); ... ...
还是使用旧方式更好?
var blaPage = new BlaBlaPage (); await Navigation.PushAsync (blaPage);

@matteopiccioni我建议这样做

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

并使用
gotoasync("blabla")

我现在意识到它的感觉是一样的,但随着功能的增长,让所有这些东西通过 Shell 系统运行将变得更加相关

真的是为每个人添加 RegisterRoute 的正确方法吗?

如果这成为一个痛点,我们正在考虑添加一些功能,这些功能只会对页面进行程序集扫描,甚至可能是一些将生成这些路由的编译时功能。

这里的主要问题是任何类型的反射都会减慢您的应用程序的速度,因此在启动时这样做会花费

@PureWeen感谢您的回答
缓慢的启动时间是 xf 中最烦人的问题之一(适用于 Android)
在启动时,我可以只添加到路由的第一级页面(shellitems 页面),并在应用程序启动后才添加其他页面(一种延迟加载 RegisterRoute)?

@matteopiccioni

所以如果你一下子就这样做

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

没关系。 我所谈论的是,如果我们最终构建了一些使用户不必这样做的东西,我们将需要权衡它与性能。 现在Routing.RegisterRoute("blabla", typeof(BlaBlaPage));不做任何反射,所以一次完成就可以了。

它所做的只是将字符串和类型添加到字典中

@jassmith @jamesmontemagno @pierceboggan哇看起来很棒。 您是否见过在 Google Pixel 上使用 Pie SDK 的 Google Contacts 应用程序? 我喜欢 UI/UX,没有标题栏和与应用程序顶部集成的汉堡包。

这个建议是否可以考虑用于您的 Shell,因为它是 Google 正在使用的一种模式,包括联系人和地图,也许还有其他人?

感谢您的时间和考虑,

卡尔

请注意,后面的所有示例都不使用模板化的 ShellContent,这在规范的其他地方进行了讨论。 未能正确使用带有 ContentTemplate 的 ShellContents 将导致在启动时加载所有页面,这将对启动性能产生负面影响。 这些示例仅用于学习目的。
幸运的是,将 ShellContents 与 ContentTemplates 一起使用通常比不使用它们更简洁。
[...]
使用 Shell 的一个主要问题是用户可以轻松地在应用程序运行开始时加载所有页面。 如果需要大量的内容页面,这种大的前置分配会导致启动性能非常差。 为了修复此模板,应尽可能使用。

对我来说,这听起来像你不应该直接使用内容,而应该使用模板。 这对我来说很有意义,那么为什么要支持直接内容方法呢? (除了简单,但它让人们用脚射击自己)。 感觉就像能够使用直接内容更像是“在进行演示时很棒 - 否则会很糟糕”的功能。

你好,
我刚来这地方。 我不确定这是否是提问的正确地方,否则请告诉我在哪里提问:
我试图做一些类似于上面指定的示例的事情:

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

但我收到以下错误:

错误 XLS0413 在类型“ShellItem”中找不到属性“ItemsSource”。
错误 XLS0415 在“ShellItem”类型中找不到可附加属性“ItemTemplate”。

@Elashi所以你希望在这里做这个想法吗
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/bindable-layouts

使用 ShellItem?

@PureWeen我希望使用这个想法 :) 。
你是说这个想法还没有实现吗?
如果它还没有实施,我可能有兴趣研究它。

@Elashi不是,但我可以看到这是 MVVM 场景的一个非常强大的功能

如果你想研究它,你能不能用你在想的基础知识来创造一个问题?

因此,通过反复试验......即使它对 shell 3.2 中的手势及其在 TheLittlePlayground 中有评论,我终生无法使用可视化包在 ANDROID 上使用手势。

我是否在笔记中遗漏了 Shell + 手势仅适用于 iphone 的内容?

@davidortinau我知道这只是一些规范,它已经关闭了一段时间,但我希望你能指出我正确的方向,因为规范指出以下任务要么已完成,要么在待办事项中发展:

  • 为 ShellContent 的 ala GPS -> 音乐 -> 打开音乐应用程序添加“子菜单”项的 API

目前,由于我无法让 GroupHeaders 工作,我希望重新设计我的 FlyoutMenu 以分为 6 个主要组,然后出现一个充满 FlyoutItems 的子菜单,将我导航到我预先确定的路由。

我的用例是我有 50 多个选项可以显示,并将其置于滚动状态不是 UI 友好的,但是我需要让我的用户高效地访问每个选项,而不必无休止地滚动。 从 UI/UX 的角度来看,根据每个选项的总体主题进行分组是最有意义的。

您能否说明一下开发/生产方面的情况? - 或指向我实现它的代码库的方向,以便我可以学习? (我只使用 Xamarin 1 个月,所以我对一些可用资源还是陌生的)。

@TheBaileyBrew

我只是用最有可能适用于您的场景的东西在谷歌上搜索了这个 repo。 它不会是 Shell,但您可能可以在 MasterDetailPage 设置中使用它。

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

此外,他们只是将他们的许多课程材料移动并更新到 MSFT Learn(我正在通过自己来填补空白)。 可以在这里找到: https :

我会尝试通过上述。 祝你好运,欢迎登机!

大家好,我想从图库或外部存储中选择文件或照片
xamarin 表格谁来挑档呢? 该文件只有 .PDF 扩展名。 到
选择两个文件我用一个按钮所以请帮助我!!!

2019 年 5 月 23 日星期四,19:41 Anthony Cool [email protected]写道:

@TheBaileyBrew https://github.com/TheBaileyBrew

我只是用可以适用于您的场景的东西来搜索这个 repo
最有可能的。 它不会是 Shell,但您可以在 MasterDetailPage 中使用它
设置大概。

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


您收到此消息是因为您订阅了此线程。
直接回复本邮件,在GitHub上查看
https://github.com/xamarin/Xamarin.Forms/issues/2415?email_source=notifications&email_token=AK7KSYK4N3XIVP3IHOBE2P3PW3CKJA5CNFSM4EZ4GB52YY3PNVWWK3TUL52HS4DFVREXG43MVVBWWJKZ9TUL52HS4DFVREXG43MVVBWWJKZ9TW43MVDNWWWJKZ9TW43MVXWWWJKZ9TW1000000000000000000000000000000000000004
或静音线程
https://github.com/notifications/unsubscribe-auth/AK7KSYI5XKMXD7FC7HZH45LPW3CKJANCNFSM4EZ4GB5Q
.

嘿伙计们,我想根据条件添加选项卡,所以我如何使用 C# 而不是 Xaml 在 Shell 中添加选项卡,以及如何添加菜单项。

@BeleShew您的问题可能更适合于 stackoverflow 或在 forums.xamarin.com 上

@PWaliaDev你可以通过作为 shell 一部分的各种 Items 集合来做到这一点

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

虽然我假设我们是否解决了这个问题
https://github.com/xamarin/Xamarin.Forms/issues/5428

那会适合你的情况吗?

@PureWeen - 我已经根据您的链接设置了显示选项,但我正在努力解决的问题更接近@BeleShew正在处理的问题(基于每个用户创建/删除弹出项目)

修复#5428将适合我想要实现的目标。

我的应用程序拥有具有多种角色/访问权限的用户,我需要以编程方式仅向那些获得授权的用户显示菜单选项(我不希望用户看到他们 _不能_ 做什么,只看到他们可以做什么。

虽然我一直在玩这个,试图弄清楚是否有可能检查我的菜单选项并添加而不是像这段代码那样隐藏(但我必须迭代每个可能的路线和菜单选项,这会吃掉加载时间:

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 在理论上很棒,但在没有这些必须具备的功能的情况下,实际上就不行。

  1. 根据用户角色动态添加/删除外壳项
  2. 登录/注销场景或基于条件的两个单独的导航路线。
  3. 可选地,支持其他 MVVM 框架,如 Prism

在提供功能 1 和 2 之前,无法在面向业务的应用程序中使用 Shell。

@Im-PJ 为什么你认为 1 和 2 是不可能的? (很确定他们是)

3 正在进行中并在此处进行跟踪。

有谁知道是否可以从 App Shell 选项卡中获取点击事件?
相关论坛问题: https :

完全同意@Im-PJ,不明白这些功能是如何没有专门提供的。 这是使用像 Shell 这样的工具的主要原因。 任何人都可以构建滑出式菜单!

@dotMorten也许您可以通过广泛的 C# 和黑客攻击来做 1 或 2,但是我找不到任何示例或提到在运行时绑定/禁用/隐藏/添加 Shell 项目。 似乎动态功能将是该工具的主要目标。 创建一个 XML 表示以及一些路径功能是最低限度的,足以提供给营销人员,但不足以在真正的、功能齐全的移动应用程序中实际使用。

@Im-PJ

你能稍微扩展一下这些有什么不同吗?

根据用户角色动态添加/删除外壳项
登录/注销场景

目前,如果您在登录页面上,您可以使用 TabBar 或隐藏弹出导航来执行登录/注销场景

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

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

如果您在登录页面上,导航离开的唯一方法是通过代码。

这里正在进行工作以公开 IsVisible 可绑定属性
https://github.com/xamarin/Xamarin.Forms/tree/shell_isvisible

在创建 PR 之前只需要稍微改进一下

两条独立的导航路线基于条件。

您能否举例说明您目前正在尝试做什么和不能做什么?

hoi1
我正在使用 Xamarin.Form Shell

链接示例: https :

请帮我。 如何在“关于”页面中显示 Tabbar?

我需要同时拥有两个 shell 页面。
一个用于带有主页、设置、注销等页面的布局菜单
一种用于应该从家里推送的标签页
现在我必须使用“旧方式”

我需要同时拥有两个 shell 页面。
一个用于带有主页、设置、注销等页面的布局菜单
一种用于应该从家里推送的标签页
现在我必须使用“旧方式”

如果使用 Tabbedpage,则无法显示 Flyout 。 这次我想显示 Flyout 和 Tabbar。

我把所有的页面都放在以便页面显示标签栏,但我只想在标签栏中有 4 个元素(不想显示更多标签)。 怎么办?

<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>

我需要同时拥有两个 shell 页面。
一个用于带有主页、设置、注销等页面的布局菜单
一种用于应该从家里推送的标签页
现在我必须使用“旧方式”

如果使用 Tabbedpage,则无法显示 Flyout 。 这次我想显示 Flyout 和 Tabbar。

我将所有页面都放在其中,以便页面显示 Tabbar,但我只想在 tabbar 中有 4 个元素(不想显示更多 Tab)。 怎么办?

<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>

不幸的是我不能使用壳牌
我仍然在同一个应用程序中有 MasterDetailPage 和 TabbedPage(在 iOS 中我有使用 Naxam.TopTabbedPage.Forms 插件的顶部标签页)
是我的旧票

此页面是否有帮助?
0 / 5 - 0 等级