Skip to content

Instantly share code, notes, and snippets.

@martijn00
Created September 23, 2015 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martijn00/6846f5b33ac6036ebfe6 to your computer and use it in GitHub Desktop.
Save martijn00/6846f5b33ac6036ebfe6 to your computer and use it in GitHub Desktop.
Sidemenu in Xamarin.iOS using MvvmCross
public partial class AppDelegate : MvxApplicationDelegate
{
private UIWindow window;
public RootViewController RootViewController { get { return window.RootViewController as RootViewController; } }
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
var setup = new Setup(this, window);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
window.MakeKeyAndVisible();
return true;
}
}
public class CustomPresenter : MvxViewPresenter, IMvxTouchViewPresenter
{
private readonly UIApplicationDelegate _applicationDelegate;
private readonly UIWindow _window;
protected Dictionary<Type, IBaseViewController> ViewControllers;
private static bool UserInterfaceIdiomIsPhone
{
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; }
}
public Presenter(UIApplicationDelegate applicationDelegate, UIWindow window)
{
_applicationDelegate = applicationDelegate;
_window = window;
ViewControllers = new Dictionary<Type, IBaseViewController>();
}
public void Show(UIViewController viewController)
{
if (viewController is IMvxModalTouchView)
{
PresentModalViewController(viewController, true);
return;
}
// Ask if the current view wants to replace the current RootViewController
if (viewController as IBaseViewController != null)
{
if ((viewController as IBaseViewController).ParentViewControllerType == null)
{
SetRootViewController(viewController);
return;
}
}
// Add new views to the screen.
if (viewController as IBaseViewController != null)
{
Type parentViewControllerType = (viewController as IBaseViewController).ParentViewControllerType;
if (parentViewControllerType == typeof(ContainmentNavigationViewController) &&
_window.RootViewController != null &&
_window.RootViewController.ModalViewController != null &&
_window.RootViewController.ModalViewController.GetType() == typeof(PlayerRootViewController)
)
{
parentViewControllerType = typeof(PlayerRootViewController);
}
IBaseViewController parentViewController;
if (!ViewControllers.ContainsKey(parentViewControllerType))
{
parentViewController = (IBaseViewController)Activator.CreateInstance(parentViewControllerType);
}
else
{
parentViewController = ViewControllers[parentViewControllerType];
}
parentViewController.RegisterViewController(viewController as IBaseViewController);
// Only show that view if there is not already a modal-view loaded.
if (
(
(UIApplication.SharedApplication.Delegate as AppDelegate).RootViewController == null ||
(UIApplication.SharedApplication.Delegate as AppDelegate).RootViewController.PresentedViewController == null
) &&
!parentViewController.IsVisible()
)
{
Show((UIViewController)parentViewController);
}
ViewControllers[parentViewControllerType] = parentViewController;
// Closes the hamburger-menu, controled by the SidebarController if it still is opened.
// TODO: Move this to another place ... maybe by a presentation-hint?
(_window.RootViewController as RootViewController).SidebarController.CloseMenu(true);
}
else if (viewController as MenuViewController != null)
{
(_window.RootViewController as RootViewController).SidebarController.OpenMenu();
}
else
{
throw new NotSupportedException("The ViewModelController '" + viewController + "' has no definied place where it can be shown. Please update either the Presenter or the controller.");
}
}
private void SetRootViewController(UIViewController viewController)
{
// If the RootViewController was set, remove all views and clear the ViewControllers stack.
if (_window.RootViewController != null)
{
foreach (var view in _window.Subviews)
view.RemoveFromSuperview();
ViewControllers.Clear();
}
// Set the new viewController and view.
_window.RootViewController = viewController;
viewController.View.Frame = _window.Frame;
_window.AddSubview(_window.RootViewController.View);
}
#region IMvxViewPresenter implementation
public override void Show(MvxViewModelRequest request)
{
IMvxTouchView viewController = Mvx.Resolve<IMvxTouchViewCreator>().CreateView(request);
Show(viewController as UIViewController);
}
public override void ChangePresentation(MvxPresentationHint hint)
{
if (hint is NavigationRootChangedHint && _window.RootViewController as RootViewController != null)
{
// Tell that this is the next "current" item in the menu.
((MenuViewController)(_window.RootViewController as RootViewController).SidebarController.MenuAreaController).SetCurrent(((NavigationRootChangedHint)hint).ViewModel);
}
if (hint is MenuClickedHint)
{
// Clear the navigation-stack ... When logging out, this is automatically done by replacing the RootViewController.
if (ViewControllers.ContainsKey(typeof(ContainmentNavigationViewController)))
{
var navigationController = (ViewControllers[typeof(ContainmentNavigationViewController)] as UINavigationController);
navigationController.ViewControllers = new UIViewController[0];
}
if (ViewControllers.ContainsKey(typeof(PlayerRootViewController)))
{
var navigationController = (ViewControllers[typeof(PlayerRootViewController)] as UINavigationController);
navigationController.ViewControllers = new UIViewController[0];
}
}
else if (hint is MvxClosePresentationHint)
{
// Create a request and get the
var request = new MvxViewModelRequest((hint as MvxClosePresentationHint).ViewModelToClose.GetType(), null, null, null);
IBaseViewController viewControllerToClose = Mvx.GetSingleton<IMvxTouchViewCreator>().CreateView(request) as IBaseViewController;
bool closed = false;
if (viewControllerToClose != null)
{
// The parent of the viewController is most likely the one, holding the navigation stack.
var parentViewControllerType = viewControllerToClose.ParentViewControllerType;
// If there is a modal-view, it's most likely, that this view is up on the players navigation stack.
if (parentViewControllerType == typeof(ContainmentNavigationViewController) &&
_window.RootViewController != null &&
_window.RootViewController.ModalViewController != null &&
_window.RootViewController.ModalViewController.GetType() == typeof(PlayerRootViewController)
)
{
parentViewControllerType = typeof(PlayerRootViewController);
}
if (ViewControllers.ContainsKey(parentViewControllerType))
{
var navigationController = ViewControllers[parentViewControllerType] as UINavigationController;
if (navigationController != null)
{
closed = true;
navigationController.PopViewController(true);
}
}
}
if (!closed)
{
// Please implement a close mechanism ...
throw new NotImplementedException();
}
}
}
#endregion IMvxViewPresenter implementation
#region IMvxTouchModalHost implementation
public bool PresentModalViewController(UIViewController controller, bool animated)
{
_window.RootViewController.PresentModalViewController(controller, animated);
// Add swipe-down gesture to all modal ViewControllers, since you expect, that you can move them downwards, the direction they came from.
UISwipeGestureRecognizer recognizer = new UISwipeGestureRecognizer(() =>
{
(UIApplication.SharedApplication.Delegate as AppDelegate).RootViewController.DismissModalViewController(true);
});
recognizer.Direction = UISwipeGestureRecognizerDirection.Down;
controller.View.AddGestureRecognizer(recognizer);
return true;
}
public void NativeModalViewControllerDisappearedOnItsOwn()
{
// ignored
}
#endregion IMvxTouchModalHost implementation
}
public class Setup : MvxTouchSetup
{
public Setup(MvxApplicationDelegate appDelegate, UIWindow window)
: base(appDelegate, window)
{
}
protected override IMvxTouchViewPresenter CreatePresenter()
{
return new CustomPresenter((MvxApplicationDelegate)ApplicationDelegate, Window);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment