MvvmCross – FlyoutNavigation, Hamburger Menu, Sliding Menu for Android and iOS

Summary

Provide a unified architecture for a FlyoutNavigation/Hamburger Menu/Sliding Menu across Android and iOS using MvvmCross.

Updates

Source Code

https://github.com/benhysell/V.FlyoutTest

Introduction

FlyoutNavigation, Hamburger Menus, and Sliding Menus (from here on out I’ll refer to this type of control as a slide out menu) all describe a popular method on mobile devices of navigating application windows via a menu that slides/flies out onto the screen providing a user multiple choices on which screen they want to navigate to next.

In my own app Goal Weight I used the popular Xamarin component FlyoutNavigation to show/hide access to settings, set goals, and view weight history.

Menu

For my latest project I’ve started development of a time tracking application that will run on Android and iOS. Thus, I found myself needing a cross platform slide out menu.

Existing Work

After Googling and researching StackOverflow I had a couple of contenders for an out of the box solution:

The only rub was neither one of these methodologies shared a common MvvmCross .Core project, and I didn’t want to support multiple/different .Core projects for different platforms. I also had experience with the FlyoutNavigation component and wanted to use it for the iOS solution. Thus I set out to create a unified architecture.

Source Code Walkthrough

The source code up on GitHub is used to demo this unified architecture…think of it as a road map on how to implement a cross platform MvvmCross slide out menu.

The demo application has four ViewModels:

  • HomeViewModel – Holds all of the ViewModels that will appear in the slide out menu
  • EnterTimeViewModel – ViewModel accessible from the slide out menu. In the demo this view is blank.
  • CreateNewJobViewModel – A second ViewModel accessible from the slide out menu. Also blank for this demo.
  • AddNewHoursEntryViewModel – A ViewModel that is created from the EnterTimeViewModel when the user presses a button on the upper right hand corner of the navigation bar.

Android Architecture

##### Background - http://motzcod.es/post/60427389481/effective-navigation-in-xamarin-android-part-1

Source - https://github.com/jamesmontemagno/Xam.NavDrawer

Android has a slide out menu built into later versions of Android called a Navigation Drawer. James Montemagno does an amazing job implementing the Navigation Drawer on Android in his blog post, so I decided to use his code as a starting point/inspiration for my .Core and .Android projects.

For a full detailed breakdown of the Android architecture read James’ blog. The short version is the HomeViewModel holds the slide out menu items and EnterTimeView and CreateNewJobView are fragments that are swapped in and out of the View as commanded by the slide out menu.

I tore through James’ GitHub code and re-implemented it in my example application to ensure I understood it well enough to keep moving forward. I liked the idea of having one ViewModel to hold all of the menu data and carried this idea over to the iOS application.

iOS Architecture

#### Warning - Although the iOS architecture works, it doesn’t “feel correct”, i.e. it has a little code smell than I would not normally feel comfortable living with. However I’m happy enough with the solution for now.

With the iOS architecture the idea is simple, construct a FlyoutNavigationController and build up the Views that will populate it in the HomeView.

First build the FlyoutNavigationController and add it to the View.

public override void ViewDidLoad()
{
    base.ViewDidLoad();
    NavigationController.NavigationBarHidden = true;
    Title = "Home";
    this.View = new UIView { BackgroundColor = UIColor.White };

    navigation = new FlyoutNavigationController();

    View.AddSubview(navigation.View);
    this.AddChildViewController(navigation);

One key point here is NavigationController.NavigationBarHidden = true;, for Views that will be managed from the FlyoutNavigationController we want to use the FlyoutNavigationController’s navigation bar and not the one supplied by MvvmCross.

Next, we’ll build up the ViewModels and menu elements for the FlyoutNavigationController. Data for the ViewModels and their names are held in the HomeViewModel

//names of the views shown in the flyout
var flyoutMenuElements = new Section();
//views that will be shown when a menu item is selected
var flyoutViewControllers = new List<UIViewController>();
var homeViewModel = ViewModel as HomeViewModel;
if (homeViewModel != null)
{
    //create the ViewModels
    foreach (var viewModel in homeViewModel.MenuItems)
    {
        var viewModelRequest = new MvxViewModelRequest
        {
            ViewModelType = viewModel.ViewModelType
        };

        flyoutViewControllers.Add(CreateMenuItemController(viewModelRequest));
        flyoutMenuElements.Add(new StringElement(viewModel.Title));
    }
    navigation.ViewControllers = flyoutViewControllers.ToArray();

    //add the menu elements
    var rootElement = new RootElement("")
    {
        flyoutMenuElements
    };
    navigation.NavigationRoot = rootElement;
}

Creating the UIViewControllers in CreateMenuItemController

private UIViewController CreateMenuItemController(MvxViewModelRequest viewModelRequest)
{
    var controller = new UINavigationController();
    var screen = this.CreateViewControllerFor(viewModelRequest) as UIViewController;
    controller.PushViewController(screen, false);
    return controller;
}

Lastly, we need to listen to two messages that will be emitted by all Views that the FlyoutNavigationController will show. One message to toggle the FlyoutNavigationController’s menu, and another to show and hide the MvvmCross navigation bar.

var messenger = Mvx.Resolve<IMvxMessenger>();
navigationMenuToggleToken = messenger.SubscribeOnMainThread<ToggleFlyoutMenuMessage>(message => navigation.ToggleMenu());
navigationBarHiddenToken = messenger.SubscribeOnMainThread<NavigationBarHiddenMessage>(message => NavigationController.NavigationBarHidden = message.NavigationBarHidden);

One last item needs to be addressed in our HomeView, setting the size of the Views that will be shown in the FlyoutNavigationController.

public override void ViewWillAppear(bool animated)
{
    base.ViewWillAppear(animated);
    navigation.View.Frame = UIScreen.MainScreen.Bounds;
    navigation.View.Bounds = UIScreen.MainScreen.Bounds;
}

If we fail to set the FlyoutNavigationController View.Frame and View.Bounds the FlyoutNavigationController will draw all of our views at 2x the Frame size than they should be.

Our HomeView is now complete, let’s take a look at EnterTimeView.

EnterTimeView

The EnterTimeView is going to show the slide out menu button that when toggled will show the slide out menu, plus it will show another view, the AddHoursEntryView with a button on the upper right of the navigation bar. We’ll add two buttons to the navigation bar with delegates to send message back to the HomeView to perform these actions.

public override void ViewDidLoad()
{
    View = new UIView { BackgroundColor = UIColor.Blue };

    base.ViewDidLoad();
    Title = "Enter Time";
    NavigationItem.LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Pause,
                                      (delegate
                                      {
                                       //message to show the menu
                                       var messenger = Mvx.Resolve<IMvxMessenger>();
                                       messenger.Publish(new ToggleFlyoutMenuMessage(this));
                                       }));
    NavigationItem.RightBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Add,
                                       (delegate
                                       {
                                       //hide MvvmCross navigation bar and show next view
                                       var messenger = Mvx.Resolve<IMvxMessenger>();
                                       messenger.Publish(new NavigationBarHiddenMessage(this, false));
                                       var viewmodel = ViewModel as EnterTimeViewModel;
                                       if (viewmodel != null) viewmodel.ShowFirstView();
                                       }));
}

AddHoursEntryView

Since we are showing the navigation bar for MvvmCross when we show AddHoursEntryView we need to send a message back to the HomeView to hide it again once AddHoursEntryView is dismissed by the user via the back button.

public override void ViewWillDisappear(bool animated)
{
    if (!NavigationController.ViewControllers.Contains(this))
    {
        // Back button was pressed.  We know this is true because self is no longer
        // in the navigation stack, hide MvvmCross's navigation menu
        var messenger = Mvx.Resolve<IMvxMessenger>();
        messenger.Publish(new NavigationBarHiddenMessage(this, true)); 
    }
    base.ViewWillDisappear(animated);
}

With this last step we have a working slide out menu in iOS that shares a common .Core solution with the Android project.

Conclusion

I have the warning about the iOS code smell because of the extra steps we need to take in the Views to toggle the menu and show/hide the MvvmCross navigation bar. I can’t place my finger on the exact code smell, the solution works…but to me just doesn’t feel “correct” in an Ivory Tower sort of way.

That being said, I believe the extra messaging is a small price to pay to use the FlyoutNavigation component without modification, and to have iOS and Android share a common .Core project.

Go grab the code and try it out, https://github.com/benhysell/V.FlyoutTest

Goal Weight

Just a quick post to announce I’m on the app store!

https://itunes.apple.com/us/app/goal-weight/id693001074

http://goallineapps.com/app/goal-weight/

 

Are You an Athlete?

Lord Stanley’s Cup

I grew up playing hockey.  My parents had me on the ice when I was two, and I have been playing ever since.  Growing up, winters were spent traveling every weekend throughout upstate New York, and weeknights were spent at practices in rinks that only had three solid walls, the forth being a tarp.

Summers were spent traveling from hockey camp to hockey camp, picking up new techniques, and learning edge control from a figure skating coach who emigrated from the USSR.  Once we were home in the summer my brother and I would break out the street hockey nets and start pickup games in front of our house.

It is safe to say hockey dominated my childhood.

The Transition

After high school I stopped playing competitively.  Now, twice a week I break out the equipment.  Pickup hockey is on Sunday night, and Tuesday is league night.  My league team won the championship last fall, yes I am a member of a championship team, a championship beer league team.

Transitioning from competitive hockey to a beer league can be jarring at first.  For one, no more contact.  The game completely changes when you know you are not going to be hit.  Secondly, the amount of ice I see in any given season is drastically less; there are no practices in a beer league.

There are a couple of upsides to playing in a beer league.  Since I know I’m not going to be hit anymore I participate in a lot more risky plays than I did in the past.  Fancy passes, dekes between the legs, having a little “fun” on the ice talking to the players on the other team, most of these things would have been a “no no” in competitive hockey.  Now, however, since nothing is really on the line every game is a fun game where I can go out and really enjoy playing for the sake of playing.

Plus, let’s not forget about the beer in the locker room after the game.  One really couldn’t call it a beer league if there wasn’t beer in the locker room after the game.

I’m not longer striving to be an athlete in hockey, but I am still out there enjoying the game I grew up playing.

The Athlete’s Mentality

Athlete’s practice day in day out, hit the gym, run on their off days, and are constantly preparing for their next game.  Beer league players pick up the equipment once or twice a week, enjoy a relaxing game, and get up the next morning and head into work.  For most of us we can no longer be athletes on the field, but we can each take our athletic mentality and apply it now where it counts the most, in the office.

Do you train and compete like an athlete in the office, or are you merely showing up, collecting a paycheck, and putting in a beer league performance?

To see if you are a beer leaguer or still working on making it to the pros ask yourself a few questions:

Do you read about your industry?

I feel reading is key to staying a head in software development, a topic I have touched on before in My Digital Reading List, http://benjaminhysell.com/archive/2009/01/my-digital-reading-list/.

  • Athletes read about their industry in their spare time.
  • Beer leaguers enjoy not knowing about what is happening outside of their cubical.

Do you try new techniques, software packages, and play with new hardware?

Our industry moves fast, staying on top of what others are doing, researching, and implementing is key to staying ahead of the curve.

  • Athletes are always playing with the latest and greatest, they know when to stay with what works, or jump to newer technologies.
  • Beer leaguers wait to be told what hardware and software they should use.

Do you try to learn about tools and techniques outside of your core field of competence?

There are a lot of other industries out there besides software development,

::I know I was shocked too when I heard this news, but there really is!::

…what can we learn from those industries and bring back to our own?  The restaurant industry has been working with and managing teams of people for decades, do they have tools or techniques we could then apply to software development?

  • Athletes learn about other industries outside of their own to learn from them, and see how they would fit in with their primary fields.
  • Beer leaguers have already found their set of tools and don’t want to know what others are doing.

One might not be able to “go pro” in their job, but who are you likely to want to hire, work with, start a startup with, given the chance?

Breaking Down the Game Film – Voting with Your Dollars

“Breaking Down the Game Film” is a term commonly used to analyze tape from an already played sports game to dissect what went right and what went wrong.  In this series I’ll be taking published articles from around the web and break them down.

Topic: Voting with Your Dollars

Article: “Will Anyone Pay for Anything”

Author: Guy Kawasaki

Links: https://www.openforum.com/idea-hub/topics/the-world/article/will-anyone-pay-for-anything-guy-kawasaki and video http://www.building43.com/videos/2009/07/24/will-anyone-pay-for-anything/.

Guy’s article sums up the video nicely, but I highly suggest watching the video just so you can hear what the panelist say with your own ears.

In the event you are short on time, I’ll save you the click through to the article and the video and sum them both up here:

Guess what teenagers and twenty-somethings are willing to pay for online?

NOTHING!

There were only two services any of the panelists were willing to pay for:

  • Gmail
  • Xbox Live

Facebook, Twitter, YouTube…they won’t pay for any of them.  This panel never clicks on banner ads, and if any of the services started charging them money to use them they would move on to find a new service to meet their needs.

Millions of users, and Facebook might loose them all if they ever wanted to charge money.

That is scary.

It turns out developers of all ages are not too different, well, it appears we don’t click on ads at least, as Jeff Atwood laments, http://blog.stackoverflow.com/2009/11/our-amazon-advertising-experiment/,

If Stack Overflow, a site that does a million pageviews a day, can’t make enough from AdSense to pay even one person half time — and let me tell you, that’s being overly generous based on the actual income it generated — how does anyone make a decent living with AdSense?

Thus, teenagers, twenty-somethings, and developers don’t click on ads on the Internet.

I then asked myself two questions:

  1. How does anyone stay in business online?
  2. What would I pay for online if it wasn’t free?

Question one has a myriad of answers that I won’t dive into in this post.  With question two I spent a few minutes and came up with this list:

  • Gmail – Nope, I would put up my own email server if push came to shove.  I already have one on standby just in case.  Better safe than sorry, :-).
  • Xbox Live – This I do pay for, mainly because there is no alternative to play the Xbox online.
  • Facebook – Gone.
  • Twitter – Gone.
  • Flickr – I have already moved to Facebook.  See above for how I feel about paying for Facebook.
  • Stackoverflow – Tougher decision, however there are too many free alternatives out there to fill the void.  Right now when I Google a programming question I’m still finding plenty of links to non-Stackoverflow sites with very good answers.  Someday, but right now, it is a no.
  • Google Reader – Plenty of alternative RSS readers.
  • All of the feeds in my Google Reader – There isn’t a feed/website in my reader that I couldn’t live without.
  • Google – Would I pay for Google?  Again, there are too many free alternatives.

It would be painful to move, change, or lose any of these services/websites, but not painful enough to pay any amount to continue to use them.

Scary thought.

Or…

What happens in a world where no one pays for anything and you are the one person who will pay for something?

You might just get everything you ever wanted.

Look at the cartoon Family Guy, from our friends at Wikipedia:

Shortly after the third season of Family Guy aired in 2001, Fox canceled the series.  However, favorable DVD sales and high ratings for syndicated reruns convinced the network to renew the show in 2004.

http://en.wikipedia.org/wiki/Family_guy

Family Guy was dead in the water, with no hope to ever see the light of day again.  Then, something crazy happened.  People voted with their dollars, bought the DVDs like crazy, and watched all of the reruns over and over and over again.  Fox woke up, picked the series back up, and Family Guy is entering it’s 8th season.

I’ve decided to start “voting with my dollars” online by monetarily contributing to the following projects that create the plug-ins I use on my blog:

I also purchased an iPhone game I normally wouldn’t have, but I bought it based on the author’s excellent blog posts.  Check out Monkeys in Space from Streaming Colour: http://www.streamingcolour.com/blog/2009/09/22/monkeys-in-space-escape-to-banana-base-alpha/ and check out Owen Goss great iPhone development blog at http://www.streamingcolour.com/blog/.

It is my hope to continue to support developers and their projects by contributing to them on a regular basis to further their development.

Next time you find a project, blog, or application you really enjoy I urge you to support it.  By voting with your dollars we have a lot more power online than we realize to influence what survives and what withers.

It is time we all start voting with our dollars!

Whose Brand are You Building?

Towards the end of 2009 there were two great articles published by two of my favorite bloggers, Joel Spolsky from Fog Creek Software and David Heinemeier from 37signals.

Joel’s post wonders if growing your company too slowly means your company is bound to die:

http://www.inc.com/magazine/20091101/does-slow-growth-equal-slow-death.html?partner=fogcreek

David responds to Joel in his own post on his blog:

http://37signals.com/svn/posts/2002-bug-tracking-isnt-a-network-effect-business

Normally, I would save each one of these links and break them down in my series “Breaking Down the Game Film,” however, there was something else here in these two posts that I thought was more interesting than their primary messages.

Scroll to the bottom of each of the posts and look at the number of comments attached to each one.  I would venture to say there is more written in the comments than in the original posts.  I’ve seen this before, but there was something that really struck me oddly as I compared and contrasted these two articles.

The idea of commenting on an article on the Internet seems to be one of the founding principals of the Internet.  Take http://www.slashdot.org, for example, Slashdot is built around people commenting on articles posted all around the Internet.  I have never found this phenomenon of people wanting to comment on other people’s work too interesting before.  In fact I would spend a considerable amount of time reading each one of the comments, never posting mind you, but normally reading the majority of the opinions listed below the articles.

Then something happened, I completely stopped reading comments on other websites.

When I first stopped reading the comments I attributed it to a lack of time-who has the time to scroll through 120 comments for just one article?  After that personal revelation I haven’t given it too much thought, however, lately, after a year of maintaining a technical blog, I realized what my real issue is with comments, and it boils down to this, whose brand are you building?

::We have a blog title, J::

David Heinemeier could have just as easily added his comments below Joel’s article, but he didn’t, he brought the conversation to his own blog.  On 37signals David controls the content, and most importantly of all, he will be able to find his comments again if he ever wants to.  He has a collection of all of his content and thoughts in one location, building his own brand, and his company’s brand on his servers and under his logo.

His thoughts won’t disappear if the server Joel posted his article on ever crashes or that company goes out of business.  His brand is being built in a location he has ultimate control over, and he can assure it never goes away if he chooses to.

Jeff Atwood has covered this topic on his own blog, referring to people who provide content to websites as “digital sharecroppers”.  Jeff doesn’t call out people who comment on blog posts directly, but rather cites the larger trend of people supplying content to the Facebooks and YouTubes of the world: http://www.codinghorror.com/blog/archives/001295.html.

Ironically, below his post the comments are full with the people doing just what he suggests they shouldn’t.

I agree with Jeff that one should focus on building their own brand.  I’m not suggesting you don’t comment on what you read on the Internet, but rather, if you feel passionately about something you have read take that thought or idea and turn it into a post on your own website, expand upon the points made by the author, and strive to control your own brand.