包装到 UINavigation 控制器中的 MvvmCross Tabs 控制器?
MvvmCross Tabs Controller wrapped into UINavigation Controller?
我正在使用 Xamarin.iOS 和 MvvmCross 5.x。我的根视图是 Tabs Controller,我希望任何显示子视图的请求都会强制在选项卡外部(而不是内部)进行堆栈导航。
所以我定义了我的根视图如下:
[MvxFromStoryboard]
[MvxRootPresentation(WrapInNavigationController = true)]
public partial class HomeView : MvxTabBarViewController<HomeViewModel>
不幸的是,根导航控制器不是 UINavigationController(正如我基于属性所期望的那样),而是本质上是选项卡视图的 HomeView,我无法实现我的目标。
然后我覆盖 ios 演示者以手动创建根 UINavigationController:
public class MySuperCoolIosViewPresenter : MvxIosViewPresenter
{
private UINavigationController _rootViewController;
public MySuperCoolIosViewPresenter(IMvxApplicationDelegate applicationDelegate, UIWindow window)
: base(applicationDelegate, window)
{
}
protected override void SetWindowRootViewController(UIViewController controller)
{
_rootViewController = new UINavigationController(controller);
base.SetWindowRootViewController(_rootViewController);
}
protected override void ShowChildViewController(UIViewController viewController, MvvmCross.iOS.Views.Presenters.Attributes.MvxChildPresentationAttribute attribute, MvxViewModelRequest request)
{
_rootViewController.ShowViewController(viewController, _rootViewController);
}
}
但此代码在尝试设置控制器 base.SetWindowRootViewController(_rootViewController)
时在 MvvmCross 的某个深处失败并出现以下错误:
System.NullReferenceException: Object reference not set to an instance of an object\n
at MvvmCross.iOS.Views.Presenters.MvxIosViewPresenter.CloseTabBarViewController () [0x00036] in <861dee92d7924acc93d876339b4b95f9>:0
at MvvmCross.iOS.Views.MvxTabBarViewController.ViewWillDisappear (System.Boolean animated) [0x0001f] in <861dee92d7924acc93d876339b4b95f9>:0
at (wrapper managed-to-native) ObjCRuntime.Messaging:void_objc_msgSend_IntPtr (intptr,intptr,intptr)
at UIKit.UIWindow.set_RootViewController (UIKit.UIViewController value)
如何在不为根视图创建额外的 ViewModel 和 View 的情况下实现我的目标(我不喜欢这种方法,因为在这种情况下 Android 会崩溃)
我创建了这个示例,其中包含您所需要的内容:https://github.com/rrispoli/SampleTabs
当我在寻找解决方案时,来自 MvvmCross 的人更新了框架以准确解决版本 5.1.1
的问题(我使用的是 5.1.0
)。 Ios 演示者逻辑已更新以正确地尊重 WrapInNavigationController
(之前在选项卡的情况下被忽略)。不幸的是 ShowChildViewController
在 InvalidCastException
之后失败了,但我能够通过将我的根导航控制器优先于选项卡控制器
来处理这个问题
protected override void ShowChildViewController(UIViewController viewController, MvxChildPresentationAttribute attribute, MvxViewModelRequest request)
{
if (viewController is IMvxSplitViewController)
throw new MvxException("A SplitViewController cannot be presented as a child. Consider using Root instead");
if (ModalViewControllers.Any())
{
if (ModalViewControllers.LastOrDefault() is UINavigationController modalNavController)
{
PushViewControllerIntoStack(modalNavController, viewController, attribute.Animated);
return;
}
throw new MvxException($"Trying to show View type: {viewController.GetType().Name} as child, but there is currently a plain modal view presented!");
}
// this logic goes first for the root controller
if (MasterNavigationController != null)
{
PushViewControllerIntoStack(MasterNavigationController, viewController, attribute.Animated);
return;
}
// then try to show child for the tabs
if (TabBarViewController != null && TabBarViewController.ShowChildView(viewController))
{
return;
}
base.ShowChildViewController(viewController, attribute, request);
}
我希望它能节省一些人的时间。
我正在使用 Xamarin.iOS 和 MvvmCross 5.x。我的根视图是 Tabs Controller,我希望任何显示子视图的请求都会强制在选项卡外部(而不是内部)进行堆栈导航。
所以我定义了我的根视图如下:
[MvxFromStoryboard]
[MvxRootPresentation(WrapInNavigationController = true)]
public partial class HomeView : MvxTabBarViewController<HomeViewModel>
不幸的是,根导航控制器不是 UINavigationController(正如我基于属性所期望的那样),而是本质上是选项卡视图的 HomeView,我无法实现我的目标。
然后我覆盖 ios 演示者以手动创建根 UINavigationController:
public class MySuperCoolIosViewPresenter : MvxIosViewPresenter
{
private UINavigationController _rootViewController;
public MySuperCoolIosViewPresenter(IMvxApplicationDelegate applicationDelegate, UIWindow window)
: base(applicationDelegate, window)
{
}
protected override void SetWindowRootViewController(UIViewController controller)
{
_rootViewController = new UINavigationController(controller);
base.SetWindowRootViewController(_rootViewController);
}
protected override void ShowChildViewController(UIViewController viewController, MvvmCross.iOS.Views.Presenters.Attributes.MvxChildPresentationAttribute attribute, MvxViewModelRequest request)
{
_rootViewController.ShowViewController(viewController, _rootViewController);
}
}
但此代码在尝试设置控制器 base.SetWindowRootViewController(_rootViewController)
时在 MvvmCross 的某个深处失败并出现以下错误:
System.NullReferenceException: Object reference not set to an instance of an object\n
at MvvmCross.iOS.Views.Presenters.MvxIosViewPresenter.CloseTabBarViewController () [0x00036] in <861dee92d7924acc93d876339b4b95f9>:0
at MvvmCross.iOS.Views.MvxTabBarViewController.ViewWillDisappear (System.Boolean animated) [0x0001f] in <861dee92d7924acc93d876339b4b95f9>:0
at (wrapper managed-to-native) ObjCRuntime.Messaging:void_objc_msgSend_IntPtr (intptr,intptr,intptr)
at UIKit.UIWindow.set_RootViewController (UIKit.UIViewController value)
如何在不为根视图创建额外的 ViewModel 和 View 的情况下实现我的目标(我不喜欢这种方法,因为在这种情况下 Android 会崩溃)
我创建了这个示例,其中包含您所需要的内容:https://github.com/rrispoli/SampleTabs
当我在寻找解决方案时,来自 MvvmCross 的人更新了框架以准确解决版本 5.1.1
的问题(我使用的是 5.1.0
)。 Ios 演示者逻辑已更新以正确地尊重 WrapInNavigationController
(之前在选项卡的情况下被忽略)。不幸的是 ShowChildViewController
在 InvalidCastException
之后失败了,但我能够通过将我的根导航控制器优先于选项卡控制器
protected override void ShowChildViewController(UIViewController viewController, MvxChildPresentationAttribute attribute, MvxViewModelRequest request)
{
if (viewController is IMvxSplitViewController)
throw new MvxException("A SplitViewController cannot be presented as a child. Consider using Root instead");
if (ModalViewControllers.Any())
{
if (ModalViewControllers.LastOrDefault() is UINavigationController modalNavController)
{
PushViewControllerIntoStack(modalNavController, viewController, attribute.Animated);
return;
}
throw new MvxException($"Trying to show View type: {viewController.GetType().Name} as child, but there is currently a plain modal view presented!");
}
// this logic goes first for the root controller
if (MasterNavigationController != null)
{
PushViewControllerIntoStack(MasterNavigationController, viewController, attribute.Animated);
return;
}
// then try to show child for the tabs
if (TabBarViewController != null && TabBarViewController.ShowChildView(viewController))
{
return;
}
base.ShowChildViewController(viewController, attribute, request);
}
我希望它能节省一些人的时间。