iphone


27
Aug 10

Book Review: Tapworthy

The Book

Tapworthy: Designing Great iPhone Apps by Josh Clark

“Designing a tapworthy app means designing for an economy of time, attention, and space.”

The Review

Tapworthy is an indispensable resource for developers trying to make quality mobile applications for all platforms.  While the book uses iPhone apps and user interface elements to illustrate the concepts discussed, many of the observations made about the mechanics, human interactions, and the psychology of what makes great applications are applicable to all mobile applications.

The book does a good job of exploring the user interface elements found in iOS apps and provides a good summary of how and why you would use the elements in your designs.  The coverage of this material is quite good but pales in comparison to the exploration of what goes into making a tapworthy app.  It is in this exploration of what makes a tapworthy app that I got my two main takeaways from the book.

The first is to be ruthless when cutting scope and narrowing the focus of your app.  To help developers and designers do this, a series of questions are provided and discussed.  It is amazing how quickly issues with your design arise when your ideas are subjected to simple questions like:

  • What does your app do and why?
  • What specific problem does your app uniquely solve for users?
  • What makes this app mobile?
  • What mobile context are you designing for?
  • Why would you use this app when you are away from your computer?

These questions are straightforward and may seem somewhat obvious, but they are an easy way to vet ideas.  If you can’t quickly provide a compelling answers for these questions, then you might not have a best selling app idea.  Conversely, the questions can be used to identify weaknesses that might need more attention and potentially turn a good idea into a great one.

The second takeaway was to recognize the three mobile contexts: microtasking, local, and boredom. To make a good app, you need to tightly wrap the answers to the 5Ws (who is the user, what are they doing, why are they doing it on a mobile, where are they, and when are they doing it) around one or more of these.  Something common among the most successful apps is how easy it is to identify the answers to the 5W questions plus which mobile context it applies to.  When the scope of an app is perfectly tailored to a specific scenario or use case, users will find that every tap has a payoff and accomplishing tasks within the app will seem effortless.  Efficiency becomes a feature.

The Summary

There is so much to like about this book.  Tapworthy forces us to ask the right questions in designing mobile apps and provides invaluable tips and insights about maximizing your app’s user experience.  If you are serious about making good apps, do yourself a favor and pick this book up.  You won’t regret it.


6
Aug 10

Monotouch: Flurry Analytics Bindings

The MonoTouch libraries can be found on my fork of monotuch-libs on GitHub

For my latest app I wanted to collect some analytics to see which screens and content included in the app are the most useful to users.  In evaluating my mobile analytics options, Flurry’s free of charge service and easy to use API made the decision to go with them over Google Analytics and Mixpanel an easy one.

Integrating Flurry analytics into your app is pretty easy but there is a small amount of setup to be done prior.  You will need to grab the iPhone SDK from Flurry and also register your application with them to get an API key.  The API key is unique to your application and provides Flurry a way to know who is sending events and notifications back to them to log.  The SDK includes a couple header files and the Objective-C libraries you’ll need to include and link against in your MonoTouch projects.  Once the Flurry libraries and the MonoTouch bindings have been obtained and an API key has been generated, we can integrate them into MonoTouch application and start collecting data.

Initiating data collection is as simple as calling the StartSession method with the application’s API key.  That is all it takes to start collecting basic information about your app like the amount of times it has been launched, the number of different users using it, and other bits of info like hardware version and service provider.

Here is some code showing how to turn analytics on.

using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Flurry; // include the MonoTouch binding lib

namespace Foo
{
    [Register ("AppDelegate")]
    public class AppDelegate : UIApplicationDelegate
    {
        public const string FlurryApiKey ="...";

        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            // 1 liner to kick the session off
            Flurry.FlurryAPI.StartSession(FlurryApiKey);

            // Do you app thing here...
        }
    }
}

If more detailed analytics are desired, there are additional methods available to help you glean whatever meaningful information you need from your application.  The example below shows how you can automatically track the changes in navigation within a tab bar.  When you pass a UINavigationController or a UITabBarController to the CurrentPageViews method, each navigation action as you move from one view or tab to another gets tracked.  This is ideal for seeing which parts of your app users are interacting with the most.

using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Flurry; // include the MonoTouch binding lib

namespace Foo
{
    [Register ("AppDelegate")]
    public class AppDelegate : UIApplicationDelegate
    {
        public const string FlurryApiKey ="...";

        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            // 1 liner to kick the session off
            FlurryAPI.StartSession(FlurryApiKey);

            // create a navigatable controller to watch...
            UITabBarController tabBarController = new UITabBarController();

            // ...and pass it to CurrentPageViews.
            FlurryAPI.CurrentPageViews(tabBarController);

            // Do you app thing here...
        }
    }
}

I am touching on just a few things that you can do with Flurry.  The SDK docs describe a number of other things you can do like creating and logging custom events and tracking how much time is spent performing activities.  I’d recommend checking them out after you download the libraries.

I’ve just started collecting analytics during beta testing and things appear to working smoothly.  If you find any issues with the MonoTouch bindings please let me know.  Enjoy!


1
Feb 10

iPhone Wireframes

I stumbled across a great collection of iPhone wireframe templates tonight while going through my feeds.  It got me thinking about the process I’ve been using to layout and design the app I am working on.

I’ve been using regular 3 x 5’ notecards to sketch out different screens for the iPhone app I am working on.  On the ruled side I’ll scribble notes and call out must/should/wish components of the screens to help prioritize features.  On the blank side I’ve been sketching out wireframes of the screens to help get a feel for the UI and flow of the app.

cards_laid_out

I’ve played around with Balsamiq and, while the tool is fantastic, I find myself still partial to the notecards.  With the same rough dimensions of the iPhone and the flexibility of being able to quickly rearrange and reorder the screens, the cards suit my preferences as a visual-spatial learner well. 

As with most tools and techniques, personal preference plays a large role in how and when they’re employed.  I always enjoy checking out how other people work and try and steal glean ideas from them.  I’ve found the following blogs pretty useful for design, usability, and UX.  I hope they help inspire you to create something cool.

I ♥ wireframes
information aesthetics
everydayUX
Sender 11


28
Nov 09

Monotouch: UIAlertView + UITextField = Crazy Delicious

If you have ever tried to buy or install anything from the App Store or iTunes on your iPhone, then you certainly have been prompted for your password by a screen that looks like this:

itunes_pw_iphone

The control used by Apple to prompt you for your password isn’t available out-of-the-box in Cocoa Touch, but fortunately it is pretty easy to roll your own.  I’ve put together a sample project that shows a couple different techniques that are available for creating and customizing the control, and I’ll go over a few of them here.

The stock UIAlertView control consists of a title label, message label, and typically one or more buttons.  It is important to note that in Monotouch, a default button setup isn’t configured, and buttons have to be added explicitly.  If a UIAlertView is configured without any buttons, then dismissing the control will have to be done programmatically because the user will have no way to dismiss the control.  In both of my examples I’ve configured the control to have two buttons (Cancel and Ok), but I could have gotten by with just one.  If only one button is used, it is important to also note that the button is considered the Cancel button by the control, and the CancelButtonIndex property will refer to that button.

Basic_UIAlertView

The easiest way to go about composing a UIAlertView with a UITextField is to create an instance of a UITextField and add it as a sub-view.  Since you’re adding a layer on top of UIAlertView’s view, the key will be fitting this new control into the UI.  There are two ways of going about this.  The first and maybe most obvious way to solve this problem is to make some room between the message label and buttons for the text field ala the iTunes password prompt.  Since the UIAlertView control has already been laid out, moving those controls around within the frame is not as straight forward a task as it may seem.  Before we tackle that we will explore a simpler method that overlays the text field directly on top of the message label.  You sacrifice being able to display an additional message to the user, but the end result looks professional and is very easy to implement.  This will also be the basis for getting the control to have the same look and feel as the iTunes password prompt, so it is important to understand this prior to attempting to move the controls around.

The key to overlaying the text field on top of the message label is setting the bounding rectangle for the UITextField.  The bounding rectangle is where the text field draws the box in which a user enters text.  For our purposes, the rectangle needs to be drawn in between the title label and the buttons.  It is important to make sure that it covers the area where the message label is drawn.  Thanks to the work of others we know that if we start drawing the text field at the x,y offset of 12,45 that the text field will hide the message label.

The code to overlay the text field is as follows:

void PromptForName(HandlerToUse handlerType)
{
    UITextField tf = new UITextField (new System.Drawing.RectangleF (12f, 45f, 260f, 25f));
    tf.BackgroundColor = UIColor.White;
    tf.UserInteractionEnabled = true;
    tf.AutocorrectionType = UITextAutocorrectionType.No;
    tf.AutocapitalizationType = UITextAutocapitalizationType.None;
    tf.ReturnKeyType = UIReturnKeyType.Done;
    tf.SecureTextEntry = false; 

    UIAlertView myAlertView = new UIAlertView
    {
        Title = "Please enter your name",
        Message = "this line is hidden"
    };

    myAlertView.AddButton("Cancel");
    myAlertView.AddButton("Ok");
    myAlertView.AddSubview(tf);
    // More Setup Goes Here
    myAlertView.Show ();
}

The method starts by instantiating a UITextField control with a bounding rectangle passed via its constructor.  The rectangle itself is constructed with four parameters via its constructor: the first two parameters set the x and y offset from the origin point of the control, and the last two parameters set the size of the drawing area.  After the initial construction of the UITextField, a few additional properties are set to customize the display. 

Among the properties set is the SecureTextEntry.  Setting this property to true will make the text field act like a password field and hide all the characters that you’ve entered.  Once the text field has been created and initialized, we move on to creating a UIAlertView.  Via object initialization, the Title and Message properties are set with some text.  Finally, two buttons are created, and the text field is added as a sub-view to the UIAlertView.  Calling the show on the UIAlertView causes the alert to pop up.  Below you can see the rendered control.

TextField_As_Subview_UIAlertView

So now that we have the basic control setup, we can tweak it so that the text field and the message label can both be displayed.

If you recall our custom UIAlertView control is currently composed of two UILabels, two UIButtons and a UITextField that we added.  The UILabels are derived from UIView and is not a subclass of UIControl; whereas, the UIButton and the UITextField are both derived from UIControls.  Since we want to position the UITextField beneath the labels, we can use this knowledge to selectively shift only the UIControls in the view down leaving the title and message labels in place.

To accomplish this task the following steps need to be performed:

1) The control height needs to be increased to make space for the text field and provide additional space to move the UIControls.  This is done by setting the frame to a larger size.  The frame will be increased by the height of the text field plus a buffer, so the control has space between it and the others.

This is what the frame looks like after being enlarged:

FrameEnlarged_CustomUIAlertView 


2) Once the frame has been enlarged, we’ll loop through the sub-views looking for UIControls and adjust only those types down by the same text field plus buffer offset

Here is what the control looks like after each UIControl is found during the iteration through the sub-views.

FirstUIControlShifted_CancelButton

SecondUIControlShifted_OkButton

FinalUIControlShifted_TextField

Here is the code that does the control adjustment:

public class TextFieldAlertView : UIAlertView
{
    private UITextField _tf;

    // ... 

    private void AdjustControlSize()
    {
        float tfExtH = _tf.Frame.Size.Height + 16.0f;

        var frame = new RectangleF(this.Frame.X,
                                    this.Frame.Y - tfExtH/2,
                                    this.Frame.Size.Width,
                                    this.Frame.Size.Height + tfExtH);

        this.Frame = frame;

        foreach(var view in this.Subviews)
        {
            if(view is UIControl)
            {
                view.Frame = new RectangleF(view.Frame.X,
                                            view.Frame.Y + tfExtH,
                                            view.Frame.Size.Width,
                                            view.Frame.Size.Height);
            }
        }
    }
}

So now that the desired look and feel of the control has been established, it is time to wire up the control.  There are a couple options for handling events generated by the control: one is more in line with how Cocoa handles events, and another that is similar to how .Net works. 

The Cocoa way to wire up delegates involves subclassing a special delegate class associated to the control and selectively overriding the methods for the actions you want to customize.  In the case of the UIAlertView control, that delegate class is a UIAlertViewDelegate.  The delegate class includes overridable methods like Clicked where you can define the actions to take when a button on the control is clicked or where you can extend behaviors by overriding methods like Preseneted which is called after the control has been displayed to the user.

The .Net way to wire up events is to provide specific delegates for specific events.  To make interacting with the Cocoa Touch controls easier, Monotouch provides public events for each one of the methods that can be overridden in the UIAlertViewDelegate class.  Having the individual public events makes wiring up controls more intuitive for the .Net developer, but it is good to know about the Cocoa-style approach especially when looking at Objective-C examples and/or ADC docs.  I have examples of wiring up the control via both methods in the example source.

The last topic I’d like to cover briefly is how I encapsulated the customization of control by subclassing UIAlertView.  The key to getting the control to look right is to override the LayoutSubviews method and build out the text field, add it to the UIAlertView and shift the controls around there.

public override void LayoutSubviews ()
{
    // layout the stock UIAlertView
    base.LayoutSubviews ();

    // build out the text field
    _tf = ComposeTextFieldControl(_secureTextEntry);

    // add the text field to the UIAlertView
    this.AddSubview(_tf);

    // shift the UIControls to fit the text field
    AdjustControlSize();
}

I’ve added some more customizations to my subclassed UIAlertView control that allows you to enable the text field security via a constructor parameter and a tweak to the control’s Transform property to shift the control up so it isn’t hidden by the keyboard.  You can see those changes and the entire working example here on github.

Enjoy.

Links to some of the resources used:


22
Nov 09

Fun with Monotouch and Multi-Level Table Views without Interface Builder

With the recent release of  Monotouch, which enabled development for the iPhone/iPod Touch platform using C# and .Net, it seemed like the perfect time to take a swing at mobile app development.  The strong appeal of being able to leverage my C# and .Net experience while scratching an itch that I have had for a few apps was more than enough to entice me to order a brand new Mac mini and start learning the Cocoa framework.

My pet app project requires some pretty basic multi-level tabular data visualization, so that was the first thing I attempted to tackle.  I started my learning endeavor by reading the view controller programming guide from Apple’s ADC and working through a few of the tutorials listed on the Monotouch site.  One of the example tutorials listed was for a basic RSS reader.  Armed with his guide, I got up and running with a basic table view allowed me to drill down one level deep and return to the root via navigation button.  This was a great introduction and the easy to follow steps combined with the screenshots certainly hit the mark; however, this was not quite the layout I was looking for.

The data that I wanted to display calls for more than just a list-view-to-detail-view relationship that the RSS reader implemented.  As a beginner trying to figure out how to wire up my custom table controllers to each other and the navigation controller all via Interface Builder resulted in a lot of thrashing and a lot of ugly code.  I eventually was able to roughly approximate the behavior I wanted, but it was pretty obvious to me there had to be a better way.

I set out to see if I could find more Monotouch examples to see if I could pick up some tips and stumbled across Craig Dunn’s blog.  Craig not only put together apps for the Monospace and PDC conferences (and graciously provided the source) but also posted a Roget’s Thesaurus app that was just what I was looking for.  It was a simple app, but it had all the elements in play that I was looking for and an incredible diagram that tied it all together.

One of the key tips and tricks I picked up from Craig’s code was how easy it was to cut out the Interface Builder from the process.  I also generally tend to avoid using the designer whenever possible in Visual Studio but here it was a key factor in my understand.  This isn’t to say that I’d never use the Interface Builder again or that it doesn’t have its uses because it does but there was too much magic going on in how Monotouch links up the XIBs to their backing C# classes.  It wasn’t until I started explicitly creating views and view controllers instead of trying to wire them up after the fact did I start to understand how things were supposed to interact.

To implement a custom UITableViewController you need to set two properties with custom classes and override a method which is invoked by the framework when the view controller is loaded.  You’ll need to set the TableDelegate and DataSource properties on the controller with your own implementations of UITableViewDelegate and  UITableViewDataSource.  The implementation of the table delegate allows you to customize how the table will respond to certain events and the data source implementation provides not only the data the table uses but also how that data is to be displayed within the table.  Typically the ViewDidLoad method is overriden to perform the view setup work needed during initialization of the view controller.  Within the method the TableDelegate and DataSource properties can be set.

Example setting the TableDelegate and DataSource via the ViewDidLoad method:

namespace MultiLevelTableView
{
    [MonoTouch.Foundation.Register("RootViewController")]
    public partial class RootViewController : UITableViewController
    {
        class DataSource : UITableViewDataSource { /* Impl Here */ }

        class TableDelegate : UITableViewDelegate { /* Impl Here */ }

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

            TableView.Delegate = new TableDelegate (this);
            TableView.DataSource = new DataSource (this);
        }
    }
}

Example setting the properties during UITableView construction:

namespace MultiLevelTableView
{
    [MonoTouch.Foundation.Register("RootViewController")]
    public partial class RootViewController : UITableViewController
    {
        UITableView tableView;

        class DataSource : UITableViewDataSource { /* Impl Here */ }

        class TableDelegate : UITableViewDelegate { /* Impl Here */ }

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

            tableView = new UITableView()
            {
                Delegate = new TableViewDelegate(this),
                DataSource = new TableViewDataSource(this),
            };

            //You can set more properties here like size and
            //location in the frame etc.

            this.View.AddSubview(tableView);
        }
    }
}

The meat of the table view controller falls in the implementations of the DataSource and TableDelegate.

A basic DataSource setup involves overriding two methods used by parent controller.  The RowsInSection method tells how many rows need to be displayed in the table and the GetCell method returns a cell view which was customized for display by setting the text and display properties.

class DataSource : UITableViewDataSource
{
    static NSString kCellIdentifier = new NSString ("MyIdentifier");
    RootViewController tvc;

    public DataSource (RootViewController tvc)
    {
        this.tvc = tvc;
    }

    public override int RowsInSection (UITableView tableView, int section)
    {
        return tvc.RootData.Count;
    }

    public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
    {
        var cell = tableView.DequeueReusableCell (kCellIdentifier);

        if (cell == null)
        {
            cell = new UITableViewCell (UITableViewCellStyle.Default, kCellIdentifier);
        }

        cell.TextLabel.Text = tvc.RootData.ElementAt(indexPath.Row);
        cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
        return cell;
    }
}

The TableDelegate is where the behavior of the table to various events is defined.  It is here in which we load up the next view to display when a user clicks on a cell.   A basic implementation of a table view delegate involves overriding the RowSelected method with instructions on what to do with the row now that it has been selected.  If the node selected happened to be a leaf node for example we might load up the detail’s view to display the nodes properties or if the node was the parent of more child nodes we would load another list view to continue to drill down into the data.  In our case we want to drill down to the next layer of data which is managed by the SubGroupViewController.

class TableDelegate : UITableViewDelegate
{
    RootViewController tvc;
    SubGroupViewController sgvc;

    public TableDelegate (RootViewController tvc)
    {
        this.tvc = tvc;
    }

    public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
    {
        // get info from selected row
        string selectedGroup = tvc.RootData.ElementAt(indexPath.Row);

        // load up new controller to display
        if(sgvc == null)
            sgvc = new SubGroupViewController(selectedGroup);

        // push the controller on the navigation stack
        tvc.NavigationController.PushViewController(sgvc, true);
    }
}

The hang up for me with using Interface Builder to try and get the multi-level table views wired together was mostly due to not being familiar with the objects I was dealing with and not understanding what properties are needed to be initialized so the framework can display them correctly.  Approaching the problem via the Interface Builder created a lot of noise that made seeing what was really needed to wire these table view controllers with the navigation controller difficult.  In this case the the pre-packaged templates and generic layouts provided by Monotouch and Interface Builder were more of a hindrance than help but that is to be expected while learning a new technology.

I’ve packaged up my implementation of a multi-level table view app and put it on github.  If anyone is looking for straight-forward, simple example of nesting table views hopefully this will help.

I also recommend checking out the following links which helped me immensely: