Tuesday, 6 October 2009

MonoTouch "iSOFlair" 2.0

The original iSOFlair post was purely a demonstration of using Settings.bundle root.plist to drive the iPhone Settings application. It's just a bit of fun with the "Flair" feature of stackoverflow.com and related sites.

Since then I've incorporated:
  • Simon's Page Control sample (with added Page Control handling)
  • Download and save image via HTTP
  • Shake gesture support
  • Screen capture to Photos, filesystem
  • Set the badge on the application's icon
This is what it looks like:

and you can download the MonoTouch v1.1 source code to try for yourself.

Settings via root.plist
Configuring the iSOFlair application to show a particular user's statistics is done by the built-in iPhone Settings on the home screen. Creating the Settings.bundle and root.plist is covered in this post.

Page Control
Simon's sample makes it easy to set-up a Page Control with swiping however it's also possible to move between 'pages' by touching to the left or right of the dots. I added this delegate to FinishedLaunching to handle that case:
// handler for when the user navigates via the pager, rather than swiping
pageControl.ValueChanged += delegate(object sender, EventArgs e) {
var pc = (UIPageControl)sender;
double fromPage = Math.Floor((scrollView.ContentOffset.X - scrollView.Frame.Width / 2) / scrollView.Frame.Width) + 1;
var toPage = pc.CurrentPage;
var pageOffset = scrollView.ContentOffset.X + scrollView.Frame.Width;
Console.WriteLine("fromPage " + fromPage + " toPage " + toPage);
if (fromPage > toPage)
pageOffset = scrollView.ContentOffset.X - scrollView.Frame.Width;
PointF p = new PointF(pageOffset, 0);
list[toPage].ViewController.BecomeFirstResponder(); // so it can "accept" shakes
// so we can change the 'badge' on the application icon
maxPageVisited = maxPageVisited<toPage?toPage:maxPageVisited;
Download, save and display PNG in UIImage
With using System.Net added to the file, the following code will download a remote image, save to the filesystem on the iPhone and set that image to display in a UIImage control on your view:
string ImagePath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
ImagePath = Path.Combine (DocumentsDirectory, Site.PreferencesPrefix+"gravatar.png");
WebClient wc = new WebClient();
Uri uri = new Uri(gravatarUrl);
wc.DownloadFile (uri, ImagePath); // saves to filesystem
catch (Exception ex1) {Console.Write("oops");}
//UIImage img = UIImage.FromFile (ImagePath); // WHY does this break???
UIImage img = UIImage.FromFileUncached(ImagePath); // BUT this works???
if (img != null)
this.imageAvatar.Image = img; // displays on View
Shake gesture
Responding to the iPhone OS 3.0 'shake' gesture was covered in this post. As I said before, showing the network activity indicator UIApplication.SharedApplication.NetworkActivityIndicatorVisible=true; and then false is a good idea so the user knows that something is going on!

Screen capture
Using UIGraphics ImageContext to take a screenshot was covered in this post.

Set badge
The 'badge' is pretty contrived in this example. Every time the application starts (in FinishedLaunching) I start the badge at '4' then during paging we reduce the count for each page that has been viewed. Just before the app closes (in WillTerminate) we set the badge via
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 3 - maxPageVisited;
so that it is effectively showing the number of 'unviewed' panels in the application for the last execution.

You can download the MonoDevelop solution to try it for yourself. The c# files are also listed below for your perusal:


  1. I loved all the small elements that are starting to get together in a nice application.

  2. Did you ever figure out why UIImage.FromFileUncached works but UIImage.FromFile does not? I just encountered that for a file in the documents folder.

  3. Can't get the sample to compile - error: /Users/rickgross/Desktop/monotouch-samples/iSOFlair20/iSOFlair/Settings.bundle/Root.plist(1,1): Error: Text node cannot appear in this state. file:///Users/rickgross/Desktop/monotouch-samples/iSOFlair20/iSOFlair/Settings.bundle/Root.plist Line 1, position 1.

    Any thoughts?

  4. Rick, I have seen that when the plist ends up in the wrong format. Double-click to open the plist in the Property List Editor then choose Save As and make sure the File Format is "XML Property List".

    Also, FYI, this code is now available on GitHub
    so you could also try grabbing the plist file from there.