Mono and the Web

I finally got a chance to start fooling around with the MonoDroid/Touch development tools that I bought over a month ago, trying to display a web page in a native app. (The reason I chose that task is because of a conversation I had with Mat Brogie earlier in the week).

I started on Friday with MonoDevelop on Windows (couldn’t get Visual Studio 2010 to compile successfully), following the Xamarin Web View example and managed to get it up and running quite quickly with the URL for The Curatorium, a boutique store in East Providence that I’ve thought should have its own dedicated smartphone app.

 

Once I got the site displayed in a view I thought it would be cool to provide some shortcut keys for the various links using an options menu.

Here’s where it got interesting. The Android developer’s site says you should define an options menus in a XML menu resource and then “inflate” the resource file into a menu object using the following Java code:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
     MenuInflater inflater = getMenuInflater();
     inflater.inflate(R.menu.game_menu, menu);
     return true;
}

The MonoDroid Activity has an OnCreateOptionsMenu event but they didn’t implement the getMenuInflater() method. I did figure out how to create Option menu items programmatically using the menu.Add method, but I really wanted to follow the best practice of declaratively defining the menu instead of creating it in code.

First I defined my menu in an XML menu resource, saving it the Resources/Layout/ folder:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@+id/shop"
          android:icon="@drawable/ic_menu_creditcard"
          android:title="Shop"/>
     <item android:id="@+id/hours"
          android:icon="@drawable/ic_menu_clock"
          android:title="Hours"/>
     <item android:id="@+id/directions"
          android:icon="@drawable/ic_menu_location"
          android:title="Directions"/>
     <item android:id="@+id/contact"
          android:icon="@drawable/ic_menu_inbox"
          android:title="Contact"/>
</menu>

The PNGs referenced by the <item> android:icon attributes are stored in References/Drawable/ folder.

Next step was figure out how to inflate the menu resource without a getMenuInflater() method. Some digging through the Xamarin API documentation revealed that the MenuInflater class has an Inflate() method. So instantiating a new MenuInflater a

public override bool OnCreateOptionsMenu (IMenu menu)
{
     MenuInflater _inflater = new MenuInflater(this);
     _inflater.Inflate(Resource.Layout.Menu, menu);
     return true;
}

The MenuInflater constructor requires a Context. I wasn’t sure how to get a bundle reference outside of the activity’s constructor and flailed around a bit until I realized that the option menu should reference the activity. Plugging in “this” as the context appears to work.

When the code is run the web view loads the web page. Selecting the menu soft key displays the context menu with text and icons. (There’s also code to display the appropriate web page when a specific menu item is selected and handle back soft key selections.)

The next step was to see how easily the MonoDroid code could be ported to MonoTouch.

On my MacBook Pro I created a HelloWebView directory. In that directory I created three subdirectories – HelloWebView_Android, HelloWebView_iOS, and HelloWebView_Common (which I ended up not using but might need in the future).

I copied the MonoDroid code from my Windows laptop. It compiled and ran perfectly the first time. I then created a new MonoTouch Single View Application solution and spent an hour or two figuring out how create a user interface Nib in XCode 4 but reference the UIKIt control outlets from within a MonoTouch view controller.

It turns out you have to set up a delegate in the ViewDidLoad() method to link the tabBar.ItemSelected event

public override void ViewDidLoad()
{
     base.ViewDidLoad();

     var urlAddress = "http://www.thecuratorium.com/schtick.htm";
     var url = new NSUrl(urlAddress);
     var urlRequest = new NSUrlRequest(url);

     webView.ScalesPagesToFit = true;
     webView.LoadRequest(urlRequest);

     tabBar.ItemSelected += delegate(object sender, UITabBarItemEventArgs e) {
          tabBar_ItemSelected(sender, e);
     };
}

To the appropriate method that handles the raised event.

public void tabBar_ItemSelected(object sender, UITabBarItemEventArgs e)
{
     switch (tabBar.SelectedItem.Title)
     {
     ...
     }
}

The Events, Protocols, and Delegates tutorial on the Xamarin web site was a great help.

Since the iPhone doesn’t have context menus, I created a TabBar at the bottom of the view for the shortcut menu items in the Android version. I struggled a bit getting the icons to show up along with the TabBarItem text but after reading the  Working with Images tutorial (also from the Xamarin site), I got it working without too much trouble after figuring out how to reference icons stored in the solution.

Overall, I’m impressed with Xamarin’s tools. It’ll be interesting to keep experimenting with them to see the level of effort required to create Android and iOS apps that share source code.

This entry was posted in Software Development and tagged , , . Bookmark the permalink.