Designing for Mobile – Cross Platform and How to do it Right

The past two days I’ve attended MobCon2012, and it’s definitely helped me understand some more things in the mobile realm.  Overall it was a great conference, and I learned a lot while I was there.

A prominent theme that persisted across multiple talks and discussions was cross platform development.  Today development firms have a multitude of cross platform development tools that allow them to write the code once and compile apps for iOS, Android, Windows Mobile, etc.  One that I knew of previously was Appcelerator, and I was introduced to iFactr while at the conference.  Everyone (including the makers of iFactr) agreed that these technologies were best suited for business driven applications where success is not dependent on a rich UI/UX experience.

Many people might ask “why?”  If you’re going to have two native apps, why the need for two different designs when it’s the same application?  The heart of the matter is that Android and iOS have two completely different design paradigms which can be easily briefed by going over their human interface guidelines.  Below I will highlight a few of those subtle but noticeable differences in these platforms, and hope that designers keep these kinds of differences in mind when designing for different mobile platforms.

Searching

At first search fields may seem simple.  Tap in them, type some text, and click search.  These behaviors and how users interact with them are different on Android than on iOS.

It’s typical for a UISearchBar to be set as the header on a UITableView.  It is easily dismissed while scrolling down, and can be quickly pulled up by tapping the magnifying glass in the alpha scroller (list of characters/icons on the right).  Need to search the list you’re in, just scroll up!

Search on Android is a little different.  First there is the matter of accessing it.  Search Dialogs are not shown by default in the UI.  They are brought up on the screen via the use of a hardware or persistent software search button (though with device fragmentation it’s also possible your users will have NO search button).  Next, they are not usually in a scrollable portion of the screen, they become a part of the ActivityBar at the top of the screen, with results shown below.  Finally, it is common for the search itself to be more global.  Where iOS returns results for the view you are on, Android searching often returns results from within any potential part of your application.

Tab Navigation

This is pretty simple, but often overlooked.  iOS has separate UI elements for navigation bars and tab bars.

Android typically merges tabs and navigation bars

Navigation Stack

The mobile terms for the navigation stack are push and pop for adding and removing views respectively.  Selecting elements/buttons are commonly used for pushing views.  The difference lies in how each OS pops back.

iOS shows a back button in the top left of the navigation bar, labeled with the title of the previous view controller.  Android has…. well…. nothing.  They don’t show a back button, they don’t show the title of previous activities.  Apps (should) just pop an activity off the stack each time the hardware/software back button is pressed.

Two exceptional talks at MobCon that discussed these differences (on a higher leve) were done by Mike Bollinger, and Andrew & Jon from the Nerdery.  Mike’s slides can be viewed here, and I’m still waiting for the Nerdery slides to go up.

I hope designers start to take note that mobile apps can be designed similar but different across multiple platforms.  Doing so will bring richer and fuller user experiences to mobile users, and will be beneficial to your applications in the long run.

Threading in iOS

Threading in applications is important, even more so when your main thread is in charge of doing all of your UI updates.  One common area to experience weak iOS code is in an UITableView that loads content from a remote source.  This post will go over a short sample app that displays a list of the five generations of Camaros, with a picture from each generation.

Now available in the App Store for $4.99!

First, let’s take a look at an example of using no threading whatsoever to load UIImages from a URL.

cell.imageView.image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]];

Since tableView:cellForRowAtIndexPath: is called on the main thread, doing this sort of image load will completely lock up our app until all of the images have been loaded.  iOS only loads UITableViewCells in view though, so our problem gets much worse once we start scrolling.

[kml_flashembed publishmethod="static" fversion="8.0.0" movie="http://blog.pintozzi.com/wp-content/uploads/2012/11/no_threading.swf" width="480" height="873" targetclass="flashmovie"]

Get Adobe Flash player

[/kml_flashembed]

The video is recorded smoothly, it’s the application that causes the jagged scrolling as each image loads for every cell brought into view.

Until recently I always backgrounded tasks with [NSThread detachNewThreadSelector:ToTarget:withObject:].  While this isn’t necessarily a bad solution, it gets really hairy when you start trying to pass multiple arguments.  To background load those images we could use something like this:

NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:urlString, @"urlString", cell, @"cell", nil];
[NSThread detachNewThreadSelector:@selector(loadImage:) toTarget:self withObject:params];
cell.textLabel.text = name;

And then defining the loadImage: method

-(void)loadImage:(NSDictionary*)params{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[params objectForKey:@"urlString"]]];
    UITableViewCell *cell = [params objectForKey:@"cell"];
    [cell.imageView performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageWithData:data] waitUntilDone:NO];
    [cell setNeedsLayout];
}

The result is definitely smoother.

[kml_flashembed publishmethod="static" fversion="8.0.0" movie="http://blog.pintozzi.com/wp-content/uploads/2012/11/detachThread.swf" width="480" height="873" targetclass="flashmovie"]

Get Adobe Flash player

[/kml_flashembed]

Still, the code is somewhat convoluted, and if we start trying to do multiple things in the background it will become very messy very fast. Enter our savior, Grand Central Dispatch.

All aboard the ^()block train!

With the release of iOS 4 us developers have had the wondrous tool that is GCD.  Sadly, I have not realized it’s full potential until iOS 6.  The same background threading can be achieved with much cleaner code.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
    NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]];
    dispatch_sync(dispatch_get_main_queue(), ^{
        UIImage *image = [[UIImage alloc] initWithData:imageData];
        [[cell imageView] setImage:image];
        [cell setNeedsLayout];
    });
});

It looks scary because some of it follows closer to a C syntax than Obj-C, but if you read it line by line it’s quite simple.  dispatch_get_global_queue() fetches us a queue that we can dispatch tasks (blocks) onto.  Creating an async call with an execution block allows us to perform code without worrying about blocking the UI.  From there we fetch the image data and then dispatch another call on the main thread/queue (retrieved with dispatch_get_main_queue()).  Within that block we can update the UI and let the cell know it needs to layout.  The best part about this method is that variable pointers are usable in each block.  We don’t need to worry about messy pointing passing, instead we can just reference each object with ease.

I’ve only recently started using Grand Central Dispatch, but it’s already helped me refactor my code to be cleaner and faster.  I’m sure I’ll be using it more heavily as time goes on and I become more comfortable with dispatch queues.

Urban Eatery with a side of Scattered

Erin and I really like to go out and eat, and the Twin Cities have more than plenty of fun places to choose from. It’s nice to have a list of fun places to go, so I’ll be tagging posts with fun places to eat as “TCeats”.

This weekend we had the opportunity to stop by Urban Eatery. I wasn’t expecting much from the name, but was pleasantly surprised by the free valet parking as we arrived. The interior decor was quite fancy, but it still had a sense of fun with chalkboard walls and specials hand written on them. The meal itself was delicious, and most certainly not overpriced. The only thing disappointing was the dessert. I had the hot apple crisp with ice cream, and while it wasn’t bad, it just wasn’t I consider worth getting.

Scattered is simply how my brain feels. Over the past 4 days I’ve been pitched 3 app ideas. I think they all sound cool, but I’ll definitely need to work on focusing on each idea. Two client projects are coming to an end, so that will definitely free up time. Tonight I go to bed with the giant giraffe pillow pet I bought Erin. He’s big and fluffy, and hopefully provides a good night sleep.

20121104-230854.jpg