4

I with to implement two types of navigation for my app, sidebar navigation and parent-child navigation at the same time. My app starts with hamburger (sidebar) menu.

First item in sidebar menu should perform reset of the navigation stack and open home view. Home view controller should start a root stack navigation so every button on the home view should open a new view, button on a new view should open another view etc.

Every other item in sidebar menu should open a new view as a dialog.

I'm using MvvmCross 5.x, and there is no sample compatible with 5.x version. Is there anyone who can point me to a usable sample?

Hrvoje Matic
  • 1,207
  • 15
  • 12

1 Answers1

12

First of I assume you are trying to implement this for iOS. In case of Android you could simply use the Navigation Drawer.

The sample on iOS is not yet converted to MvvmCross 5.x (I will start doing so a.s.a.p.), however this should be trivial. Let me try to walk you through it:

  1. Make sure you add the MvvmCross iOS Support package to your iOS project: Install-Package MvvmCross.iOS.Support -Version 5.0.2 (or use the GUI)
  2. Configure your iOS project to use the MvxSidebarPresenter by adding the following code to the Setup class in your iOS project:

    protected override IMvxIosViewPresenter CreatePresenter()
    {
        return new MvxSidebarPresenter((MvxApplicationDelegate)ApplicationDelegate, Window);
    }
    
  3. Create a view controller which acts as you flyout menu and decorate it with the MvxSidebarPresentationAttribute. This view controller will act as your menu. You can (or better should) link it to a view model which will handle the navigation part (when the user selects a menu item). This view controller could look something like this:

    [MvxSidebarPresentation(MvxPanelEnum.Left, MvxPanelHintType.PushPanel, false)]
    public class LeftPanelView : MvxViewController<LeftPanelViewModel>
    {
        ...
    }
    
  4. To make sure your home view act as a root controller simply add the MvxSidebarPresentationAttribute to the home view controller and make sure the property Panel is set to Center, HintType is set to ResetRoot and ShowPanel is set to true), like so:

    [MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.ResetRoot, true)]
    public class HomeView : MvxViewController<HomeViewModel>
    {
        ...
    }
    
  5. For all child views (opened from the home view) make sure you set the MvxSidebarPresentationAttribute with the property Panel set to Center, HintType set to PushPanel and depending if you want to display the menu button on the child pages set the ShowPanel to true or false, like so:

    [MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.PushPanel, true)]
    public class ChildView : MvxViewController<ChildViewModel>
    {
        ...
    }
    
  6. The last step is to setup the view controller for all other buttons in the menu. These can simply be decorated with the MvxModalPresentationAttribute attribute to open them as a dialog (detailed documentation can be found here). An example could look something like this:

    [MvxModalPresentation(ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen, ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve)]
    public partial class ModalView : MvxViewController<ModalViewModel>
    {
        ...
    }
    

To open the different views you can make use of the new navigation service in MvvmCross. To do so simply allow the MvvmCross IoC container to inject an instance into your view models constructor (more details can be found here):

public class HomeViewModel : MvxViewModel
{
    private readonly IMvxNavigationService _navigationService;

    public HomeViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService ?? throw new ArgumentNullException(nameof(navigationService));
    }
}

EDIT 1: To be able to show an icon on as menu button, you'll need to implement the IMvxSidebarMenu interface on the view controller that makes up the menu (see step 3). By implementing this interface you can override the default behaviour of the menu, and example can be found here (which is part of the demo MvvmCross XamarinSidebar application).

EDIT 2: I have mistakenly suggested that you can show the menu (or it's icon) button on a child view which is pushed on the navigation stack. This is not the case, child views that are pushed on the stack will not show the menu button. In these cases the ShowPanel property is ignored completely.

EDIT 3: There is a way to accomplish that pattern entirely. We can customize stack navigation UI so we can mimic something like Android toolbar. This approach works and it basically requires us to make navigation bar hidden and create our custom toolbar that has hamburger menu, back button and other buttons and put it in the upper part of the child view. Here is the code needed for close and back buttons:

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);
            };
        }
Hrvoje Matic
  • 1,207
  • 15
  • 12
Maurits van Beusekom
  • 5,579
  • 3
  • 21
  • 35
  • I implemented almost all by modifying Marcs sample project using your instructions, but two problems still persist. 1. I don't get menu button (hamburger), but only the word "Menu". 2. When child page is opened it has navigation bar (which I can hide using NavigationController.NavigationBarHidden = false), but I don't see hamburger menu when child page is active no matter I set showpanel=true, or showpanel=false). You can find my test project here: https://1drv.ms/u/s!ArCs7A3yxQw8pTdWUPhgF0EUTu-L – Hrvoje Matic Jun 12 '17 at 17:50
  • I have updated my original post to answer your additional questions. Unfortunately I have misled you a bit in saying you can show the menu icon on a child view. – Maurits van Beusekom Jun 12 '17 at 19:40
  • I appreciate your help. Are you saying that we are unable to create a navigation shown in apps like eBay or Amazon where navigating to home menu starts some kind of stack navigation, while preserving menu panel and enable user to jump to home screen at any time (except from dialogs). Is there any other approach that can help me accomplish such navigation pattern. – Hrvoje Matic Jun 12 '17 at 20:22
  • Of course this it is possible to do, however we haven't implemented it this way. In our implementation when you push an child view on the navigation stack we show an back button (as per Apple Human Interface Guidelines: "Use a navigation bar to traverse a hierarchy of data. The navigation bar’s title can show the current position in the hierarchy, and the back button makes it easy to return to the previous location. For specific guidance, see Navigation Bars.", see also [here](https://developer.apple.com/ios/human-interface-guidelines/interaction/navigation/)). – Maurits van Beusekom Jun 12 '17 at 20:29
  • @MauritsvanBeusekom nice explanation, trying to do as u advice, but got warning - can u look here - https://stackoverflow.com/q/45082154/2012219 and advice? – hbk Jul 13 '17 at 13:59