Tuesday, June 22, 2010

Iphone - The user is always right

After some amazing designer time and some scrambling to get all the UI changes in we got to let a bunch of people play with the app on actual devices, the feed back was awesome! As in extremely useful awesome.

Nothing beats first hand feedback!

Here's a few of the fun things we discovered we had to get right:

1. If the app does not respond to user touch as expected by the user, there will be confusion!

One of our views had editable text fields. Tapping a field would bring up the key pad but there was no cursor indicating that the specific text field was selected and typing would allow you to enter a value.

Result: "The app is broken!", "Um its not working?".

The funny thing is that if you had started typing you would see the values being entered, and it would work, but the lack of a prompt from the text field was enough to cause confusion. Needless to say this important issue has been fixed.

2. Very detailed views will be expected to be zoom-able.

Several of our views contain graphs, these occupy about half the full screen size. These graphs contained points and grids and axes so users would automatically try to zoom into them. Unfortunately, we had not yet put this functionality in. Currently this is a to do item on our list, but it is obvious that our users will expect this functionality, and will be disappointed if its not there.

3. Universal hatred for pop-up warnings about invalid entries.

If a user entered an invalid value, we were displaying pop-up warning messages that would tell you the valid range to use. Almost everyone who tried out the app and got a warning message automatically hated the message. Somehow it would create frustration, even when we thought we were being helpful. I guess the pop-up warnings make a user feel like they've done something really wrong and its broken while all they want is for the d#$# thing to work! We have replaced this with the more user friendly way of indicating invalid values, where a tiny red message is displayed under the text field.

4. Saving should succeed even when not all fields are complete.

If in the users mind, the information they are filling doesn't all need to be specified, then saving should work as long as some required fields have values. This allows the user to enter in the information they have in the moment and still continue using the app, and fill the rest later. Not being able to save what they have entered already discourages them from continuing to use the app or even returning to it later. So be very careful about what and how many fields are marked as required fields.

5. Respond to device orientation change.

While users didn't try or expect this with all our views, there did seem to be an expectation for the app to support this on the graph views. They expected the graph to be zoomed in and centered on device orientation change with all other elements not getting screen space. Returning to the original orientation should then return the user to the screen with the smaller graph and the rest of the view elements. Again a to do item which would be cool to have.

Well, now we all know when making other apps of some expectations and behaviors to keep in mind to ensure a wonderful user experience!

Wednesday, June 16, 2010

Iphone - The WOW factor

About a few weeks ago our little project got lucky, and received some designer time! Our design hero put together some screen shots at first, and then sent us the images and specifications that we would need. It was amazing how polished our application started to look as soon as we started to add in the changes! We were completely WOWED with the end result! See for yourself:

Images of Main Screen Before.

Images of Main Screen After.

Now a few discoveries about adding background images, specifying table and cell backgrounds, separators and text formatting.

1. Image as background

You can use an image as the background for a UIView by adding the following code in the view controller's viewDidLoad:

self.view.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"imgname.png"]];

colorWithPatternImage is a really powerful method and can be used to set images as colors for tables, cells, labels etc.

2. Specify a color not available in the interface builder

The interface builder comes with a small selection of colors (you can add more libraries though), if you don't find the color you want, you can specify any color pro-grammatically using the UIColor class. The following example uses the color #DB3F61, and calls colorWithRed, which takes in the Red, Green, Blue and alpha values. The RGB values for #DB3F61 are RGB(219,63,97), each value is divided by 255 in order to use colorWithRed:

[UIColor colorWithRed:219.0f/255.0f green:63.0f/255.0f blue:97.0f/255.0f alpha:1.0f];

You can assign this UIColor to backgrounds, and separators etc. In the following code I've applied it to the separator line defined for tables.

self.table.separatorColor = [UIColor colorWithRed:219.0f/255.0f green:63.0f/255.0f blue:97.0f/255.0f alpha:1.0f];

3. Programmatic formatting of text

If you are creating textual elements on the fly and need the text to be formatted like the rest of the application, you can do it! Below is the example of a label, with text color, shadow size and font specified. Notice that the background color for the label is set to clearColor, this is a predefined color in the UIColor class. The shadow of the text is set to whiteColor. Other defined colors are red, orange, brown etc. The color of the label text is set to color #663300 (RGB(102,51,0)), using the colorWithRed method.

CGRect frame = CGRectMake(0, 0, 400, 44);
UILabel *label = [[[UILabel alloc] initWithFrame:frame] autorelease];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:20.0];
label.text = @"This is a label";
label.shadowColor = [UIColor whiteColor];
label.textAlignment = UITextAlignmentCenter;
label.shadowOffset = CGSizeMake(0,1);
label.textColor = [UIColor colorWithRed:102.0f/255.0f green:51.0f/255.0f blue:0.0f/255.0f alpha:1.0f];

4. Grouped tables, selected row issue

When using a UITableView, and setting the style to Grouped. You'll notice that when the top or bottom cell is selected, the grey or blue is outside of the rounded corners. Also the separators disappear for any selected cell. The workaround
for this issue is to always set the cell's background color for selected and unselected. In the view controller make sure you have a reference to the cell and in the viewDidLoad add the following code:

self.myCell.backgroundColor = [UIColor colorWithRed:219.0f/255.0f green:63.0f/255.0f blue:97.0f/255.0f alpha:1.0f];

This will set the cell's regular color. Now for selected cell color use the table's didSelectRowAtIndexPath, and for the selected row set the cell's background to a different color using the same code as above. Remember to set all the other cells back to regular cell color, and for each cell in the interface builder set the Selection property to none.

Monday, May 31, 2010

Iphone - View Controllers

View controllers are one of the most fundamental building blocks of Iphone applications. How you implement the view controllers in you application determines how information is displayed to the user over multiple screens, or even within the limited space of one screen. They allow you to manage the showing and hiding of information within one screen as well as switching back and forth between screens. This article is a general overview of view controllers and has special focus on the Navigation View Controller.

There are three types of view controllers:
- Custom View Controller
- Container View Controller
- Modal View Controller

Custom View Controllers are controller objects that manage the content of one screen. Most applications will have several screens that display different information, each of these can have its own view controller that manages the presentation of data for that particular screen only.

A Container View Controller on the other hand controls other View Controllers. These are used to define navigation between several different views. A Navigation View Controller and Tab Bar View Controller are examples of Container View Controllers.

The diagram below shows an example interface with three different views that the user can navigate back and forth between, as well as a portion of the screen being used to navigate between four other views.
There are several ways the diagram's flow could be achieved in an application. Lets say we decide to go down the following scenario:

  • Each of the 7 views gets its own custom view controller.
  • Implement a main navigation controller using UINavigationController class provided by the system. This allows us to go back and forth between the three main views.
  • For the four views, that only change a potion of the screen, we have two different options: Implement a UITabBar class in the central view, that switches between the four views or display the Toolbar that is defined within the UINavigationController class. Note that we cannot use the UITabBarController class at this point since the programming guideline prohibits incorporating a UITabBarController into a UINavigationController. However, the guideline does allow having a UINavigationController within a UITabBarController.
The UINavigationViewController is an amazing class that maintains track of a navigation stack. It contains several views that help define a navigation interface: Navigation Bar, Navigation View, Custom Content and the hidden by default Navigation Toolbar. The content of the Navigation bar and Toolbar can be customized however these views do not change. The only view that changes is the Custom Content view. This view always shows the view of the view controller that is at the top of the navigation stack.

The Navigation Bar already has a default back button defined, which displays the name of the previous view's title. If the previous view has no title then the button displays "back" by default. The behavior for this button is already defined and clicking it changes the view to the previous view. Very convenient. Sadly, if the previous view had a title the button says the title of the page and you cannot simply change the text to say "back" or any other custom text. You actually have to define a custom UIBarButtonItem and assign it to the leftBarButtonItem property of the Navigation Bar. This also means that you have to define the behavior of the button as well. The middle of the Navigation Bar generally displays the view title. You can specify a custom title by setting the titleView Property of the Navigation Bar. The right side of the Navigation Bar by default displays nothing unless the rightBarButtonItem property has been set to a custom UIBarButtonItem. The rightBarButtonItem property is often used to specify a next button or a cancel button, all you have to do is put the next view on top of the navigation stack for the controller to know which view to load.

For navigating between the four sub views we used the UITabBar class. The UITabBar class allows you to define two or more tab items, clicking on which changes the selected view. The issue to note here is that placing a view within a view required a lot of fine tuning sizing wise. Even if the views properties for auto sizing are set they didn't always render correctly within each other and we had to specify size in code. Even though we were successful with this avenue, in the end it was easier and cleaner to repeat in each of the four sub views the content of the central view that was common to them and switch the whole of the central with one of these four when a Tab Bar Item was clicked.

I hope you found this introduction / summary helpful. Choosing the path that best suits your application is very important and can have many challenges: unavailable options, rules and regulations, time for fine tuning etc. This is a decision that could determine how much re-work or re-design you may have to do later on in the project.

References and recommended reading:

Thursday, May 20, 2010

Supporting navigation with the trackball

Let's talk about using the trackball in android applications.

First of all I was surprised when noticed that focus (orange background) is not visible on ListView's items. During testing application I noticed that ListView items gets focus in reality, because if we click with the trackball on item appropriate event would be handled. However, we can't see focus that is why I started investigation. Finally it was found out that it is because of background
of ListView's items. If we need to see focus we must have background color's alpha parameter 0(ex. Color.argb(0,255,255,255), hex colors). But in that case we wouldn't have real colors(colors would be darker, ex. white would be gray). That is why we have to remove background color and use default black background. And also I want to mention another limitation of ListView. It's not possible to define items which must be focusable, because ListView is doing that itself.

The second thing that shocked me was that we can't see focus on ImageView item. In our "Edit Profile" page we have a lot of elements and have a method to define sequence of focused items. The focus works correctly for all elements, but ImageView is an exception. Investigation shows that it is a known issue that is why I have to put ImageView in another view, implement selector for that view and give orange background to it when it is focused.

Third I want to speak about behavior of the trackball under tabs. Let's go through an example.We have one activity which is responsible for drawing TabHost. Under each tab we have another activity. We need to be able to reach and interact with all items on all tabs using just the trackball. With our implementation it means that we have to navigate through items in different activities which, in my point of view, is not possible.That is why for now with the trackball we can only move slider and go from one tab to another.For example we need to set a focus on tab. As soon as activity under tab is loaded focus automatically will go to appropriate element under tab.That is why if we need to navigate through tabs we must first of all go up with the trackball then change tab.

That's all for now about strange behavior of focus when using the trackball.

Monday, May 10, 2010

Managing Experimentation - Part 2

As a follow up to my first post about managing experimentation I would like to cover an interesting aspect of this project: progression tracking.

There are several ways to track progression, some subjectives and some objectives. The most pleasing one to me is a subjective one about having "working software" this is not part of the agile manifesto for nothing, in delivering quality software you need to focus on having working software at all time and sooner than later. In the case of the IPhone implementation we did have working software very early on, it was not doing much but it was working and we could see new code coming in daily. This is an important proof that the project is moving on and it makes it easy to observe if a team is heading in the right direction or not.

Another interesting objective aspect I have been watching for is new tasks creation. While this is a matter of worry (from an estimation and profitability stand point) it is a very positive sign that the team has taken ownership of their project. By constantly creating new tasks a team is showing that they are in control of the workload of the project and that they are taking actions towards ensuring that there are no loose ends.

See for yourself:

The red line is showing tasks creation while the green is showing tasks resolutions.

As you can clearly see the team has been creating as many tasks as they have been resolving since the initial task creation initiative. And this pretty much from day one. This is very positive.

Last but not least, from an objective stand point is the rate of code submission to the repository. Actually... to the code review board. Macadamian has been performing code reviews since its birth day, in doing so it is easy to track at what pace the code come in.

I have not looked at the evolution of the #KLOC but I can confirm that the team has submitted about a patch a day. While this is a little low for a team of 4, since many of us on this team were new to the IPhone programming environment this seems to be a quite decent rate.

Friday, May 7, 2010

Chart Control for Windows Phone 7

The experiences that we've gone through on Windows Phone 7 so far have been very astonishing. Loads of controls are absent from .NET Compact. You have to find a workaround for anything that's not there. This makes life bitter.
Here are a few limitations to outline. They are not encompassed with something general, just a list of what I faced so far:
  • no local database support (as already mentioned in this and this blogs)
  • no TabControl, no DatePicker (the complete list can be found on msdn)
  • no IComparer (the common IComparer is supported, but for templates it's not)
  • in usual WPF there is Button.Children, but here we don't have it
  • no ChartControl (about them we've talked on those two pages)
OK, enough of disappointments now. Here is the good part. Macadamian developed a Chart Control which you can pick up for free. The chart looks like the one in the screenshot below.

Don't pay specific attention to that outrageous pile of letters called "Parandzem". That's an Armenian name (by the way that's a female name) that I left to appear on the phone. The rest are the "Baby Weight Tracker" application left-offs, and the chart of course.

You can download the dll of the chart here.

In the coming days another control will be available to fetch - DatePicker. Stay tuned!

Thursday, April 29, 2010

New Windows Phone Developer Tools?

The news told me that a new release of Windows Phone Developer Tools has been released recently. To not copy all the lines down here of what's new in this release, here is the short and simple page to see it.
It's always nice to move on with newer stuff, isn't it? At least it is for me, so I immediately downloaded the installer from here to see what's in there. And.... boom! The screen that I get tells me it's time to go to bed:

Requires removing all my environment to proceed. Disappointment!
So I decided I should wait until I can update the tools on my machine and not install them from scratch. All in all we're busy people and uninstalling and reinstalling a whole bunch of environment (furthermore if that's going to happen once a month) does not sound very attractive.