MvvmCross 的 MvvmCross 侧边栏导航 5.x
MvvmCross sidebar navigation for MvvmCross 5.x
我要同时为我的应用实现两种类型的导航,侧边栏导航和父子导航。
我的应用以汉堡(边栏)菜单开头。
侧边栏菜单中的第一项应该执行导航堆栈的重置并打开主页视图。
主页视图控制器应该启动根堆栈导航,这样主页视图上的每个按钮都应该打开一个新视图,新视图上的按钮应该打开另一个视图等。
侧边栏菜单中的每个其他项目都应打开一个新视图作为对话框。
我正在使用 MvvmCross 5.x,并且没有与 5.x 版本兼容的示例。
有没有人可以指点我一个可用的示例?
首先,我假设您正在尝试为 iOS 实现此功能。在 Android 的情况下,您可以简单地使用导航抽屉。
iOS 上的示例尚未转换为 MvvmCross 5.x(我将开始这样做 a.s.a.p),但这应该是微不足道的。让我试着引导您完成它:
- 确保将 MvvmCross iOS 支持包添加到您的 iOS 项目:
Install-Package MvvmCross.iOS.Support -Version 5.0.2
(或使用 GUI)
通过将以下代码添加到 iOS 中的 Setup
class,将您的 iOS 项目配置为使用 MvxSidebarPresenter
项目:
protected override IMvxIosViewPresenter CreatePresenter()
{
return new MvxSidebarPresenter((MvxApplicationDelegate)ApplicationDelegate, Window);
}
创建一个充当弹出菜单的视图控制器,并用 MvxSidebarPresentationAttribute
装饰它。这个视图控制器将充当您的菜单。您可以(或更好地应该)将它 link 到将处理导航部分的视图模型(当用户选择菜单项时)。这个视图控制器看起来像这样:
[MvxSidebarPresentation(MvxPanelEnum.Left, MvxPanelHintType.PushPanel, false)]
public class LeftPanelView : MvxViewController<LeftPanelViewModel>
{
...
}
要确保您的主视图充当根控制器,只需将 MvxSidebarPresentationAttribute
添加到主视图控制器并确保设置 属性 Panel
Center
,HintType
设置为 ResetRoot
,ShowPanel
设置为 true
),像这样:
[MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.ResetRoot, true)]
public class HomeView : MvxViewController<HomeViewModel>
{
...
}
对于所有子视图(从主视图打开)确保将 MvxSidebarPresentationAttribute
设置为 属性 Panel
设置为 Center
, HintType
设置为 PushPanel
并根据您是否要在子页面上显示菜单按钮将 ShowPanel
设置为 true
或 false
,像这样:
[MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.PushPanel, true)]
public class ChildView : MvxViewController<ChildViewModel>
{
...
}
最后一步是为菜单中的所有其他按钮设置视图控制器。这些可以简单地用 MvxModalPresentationAttribute
属性修饰以将它们作为对话框打开(可以找到详细文档 here)。示例可能如下所示:
[MvxModalPresentation(ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen, ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve)]
public partial class ModalView : MvxViewController<ModalViewModel>
{
...
}
要打开不同的视图,您可以使用 MvvmCross 中的新导航服务。为此,只需允许 MvvmCross IoC 容器将一个实例注入您的视图模型构造函数(可以找到更多详细信息 here):
public class HomeViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public HomeViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService ?? throw new ArgumentNullException(nameof(navigationService));
}
}
编辑 1:
为了能够将图标显示为菜单按钮,您需要在构成菜单的视图控制器上实现 IMvxSidebarMenu
接口(参见第 3 步)。通过实现此接口,您可以覆盖菜单的默认行为,示例可以在 here (which is part of the demo MvvmCross XamarinSidebar application).
中找到
编辑 2:
我错误地建议您可以在推送到导航堆栈的子视图上显示菜单(或其图标)按钮。事实并非如此,压入堆栈的子视图不会显示菜单按钮。在这些情况下,ShowPanel
属性 会被完全忽略。
编辑 3:
有一种方法可以完全完成该模式。我们可以自定义堆栈导航 UI,这样我们就可以模仿 Android 工具栏之类的东西。这种方法有效,它基本上需要我们隐藏导航栏并创建我们的自定义工具栏,其中包含汉堡菜单、后退按钮和其他按钮,并将其放在子视图的上部。这是关闭和后退按钮所需的代码:
public override void ViewDidLoad()
{
base.ViewDidLoad();
NavigationController.NavigationBarHidden = true;
btnClose.TouchUpInside += (object sender, EventArgs e) =>
{
NavigationController.NavigationBarHidden = false;
NavigationController.PopViewController(false);
};
btnShowMenu.TouchUpInside += (object sender, EventArgs e) =>
{
var sideMenu = Mvx.Resolve<IMvxSidebarViewController>();
sideMenu?.Open(MvxPanelEnum.Left);
};
}
我要同时为我的应用实现两种类型的导航,侧边栏导航和父子导航。 我的应用以汉堡(边栏)菜单开头。
侧边栏菜单中的第一项应该执行导航堆栈的重置并打开主页视图。 主页视图控制器应该启动根堆栈导航,这样主页视图上的每个按钮都应该打开一个新视图,新视图上的按钮应该打开另一个视图等。
侧边栏菜单中的每个其他项目都应打开一个新视图作为对话框。
我正在使用 MvvmCross 5.x,并且没有与 5.x 版本兼容的示例。 有没有人可以指点我一个可用的示例?
首先,我假设您正在尝试为 iOS 实现此功能。在 Android 的情况下,您可以简单地使用导航抽屉。
iOS 上的示例尚未转换为 MvvmCross 5.x(我将开始这样做 a.s.a.p),但这应该是微不足道的。让我试着引导您完成它:
- 确保将 MvvmCross iOS 支持包添加到您的 iOS 项目:
Install-Package MvvmCross.iOS.Support -Version 5.0.2
(或使用 GUI) 通过将以下代码添加到 iOS 中的
Setup
class,将您的 iOS 项目配置为使用MvxSidebarPresenter
项目:protected override IMvxIosViewPresenter CreatePresenter() { return new MvxSidebarPresenter((MvxApplicationDelegate)ApplicationDelegate, Window); }
创建一个充当弹出菜单的视图控制器,并用
MvxSidebarPresentationAttribute
装饰它。这个视图控制器将充当您的菜单。您可以(或更好地应该)将它 link 到将处理导航部分的视图模型(当用户选择菜单项时)。这个视图控制器看起来像这样:[MvxSidebarPresentation(MvxPanelEnum.Left, MvxPanelHintType.PushPanel, false)] public class LeftPanelView : MvxViewController<LeftPanelViewModel> { ... }
要确保您的主视图充当根控制器,只需将
MvxSidebarPresentationAttribute
添加到主视图控制器并确保设置 属性Panel
Center
,HintType
设置为ResetRoot
,ShowPanel
设置为true
),像这样:[MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.ResetRoot, true)] public class HomeView : MvxViewController<HomeViewModel> { ... }
对于所有子视图(从主视图打开)确保将
MvxSidebarPresentationAttribute
设置为 属性Panel
设置为Center
,HintType
设置为PushPanel
并根据您是否要在子页面上显示菜单按钮将,像这样:ShowPanel
设置为true
或false
[MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.PushPanel, true)] public class ChildView : MvxViewController<ChildViewModel> { ... }
最后一步是为菜单中的所有其他按钮设置视图控制器。这些可以简单地用
MvxModalPresentationAttribute
属性修饰以将它们作为对话框打开(可以找到详细文档 here)。示例可能如下所示:[MvxModalPresentation(ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen, ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve)] public partial class ModalView : MvxViewController<ModalViewModel> { ... }
要打开不同的视图,您可以使用 MvvmCross 中的新导航服务。为此,只需允许 MvvmCross IoC 容器将一个实例注入您的视图模型构造函数(可以找到更多详细信息 here):
public class HomeViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public HomeViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService ?? throw new ArgumentNullException(nameof(navigationService));
}
}
编辑 1:
为了能够将图标显示为菜单按钮,您需要在构成菜单的视图控制器上实现 IMvxSidebarMenu
接口(参见第 3 步)。通过实现此接口,您可以覆盖菜单的默认行为,示例可以在 here (which is part of the demo MvvmCross XamarinSidebar application).
编辑 2:
我错误地建议您可以在推送到导航堆栈的子视图上显示菜单(或其图标)按钮。事实并非如此,压入堆栈的子视图不会显示菜单按钮。在这些情况下,ShowPanel
属性 会被完全忽略。
编辑 3: 有一种方法可以完全完成该模式。我们可以自定义堆栈导航 UI,这样我们就可以模仿 Android 工具栏之类的东西。这种方法有效,它基本上需要我们隐藏导航栏并创建我们的自定义工具栏,其中包含汉堡菜单、后退按钮和其他按钮,并将其放在子视图的上部。这是关闭和后退按钮所需的代码:
public override void ViewDidLoad()
{
base.ViewDidLoad();
NavigationController.NavigationBarHidden = true;
btnClose.TouchUpInside += (object sender, EventArgs e) =>
{
NavigationController.NavigationBarHidden = false;
NavigationController.PopViewController(false);
};
btnShowMenu.TouchUpInside += (object sender, EventArgs e) =>
{
var sideMenu = Mvx.Resolve<IMvxSidebarViewController>();
sideMenu?.Open(MvxPanelEnum.Left);
};
}