Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] - نسخه متنی

Ivo Salmre

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید











A State Model for User Interface Layout and Management


A fairly simple example is useful in demonstrating the utility of a state-machine-driven user interface. This example will show the benefits of the state machine approach for evolving user interface design. Continuing with the scenario described in Figures 13.3, 13.4, and 13.5, the code will implement the main parts of the user interface for a foreign-language vocabulary teaching game for the Pocket PC. As the application's user answers multiple-choice vocabulary questions, action will occur on a play field section of the screen reflecting correct and incorrect choices. The play field will use about 60 percent of the available screen real estate; its goal is to keep the user entertained and engaged while learning new vocabulary words. To keep things simple, for now the application's user interface code will represent the play field as a yellow rectangle bitmap displayed in a picture box. You may want to fill this picture box instead with a loaded bitmap image to supply a more realistic view of what the play field will contain and see how the play field's visibility is affected by the user interacting with the application. This application demonstrates user interface concepts using a multiple-choice game, but the concepts demonstrated here are equally applicable for applications ranging from business applications to action-oriented games; the state machine user interface model is remarkably versatile.

As shown in Figure 13.6, the mobile application's user interface has four different states:

Start screen
When the mobile device application is first started, we will want to display a screen to the users that welcomes them to the game, gives necessary instructions, and allows them an easy way to start playing. I have chosen a very simple start screen showing only a "start" button and the game play field. You may want to add text instructions or a running animation to the start screen to get the user interested in the game. In any case, the user simply clicks the "start" button and they are moved onto the next state.

Ask the vocabulary question
In this state, the mobile application prompts the user with a vocabulary question. In our code we have chosen to display the question in a TextBox control, but this need not necessarily be the case. For example, the question could be displayed in a Label control or printed on top of the play field bitmap if it makes sense to do so. If our device supports speech synthesis, we may even want to audibly ask the question. We have chosen to use a read-only text box because it meets our needs and enables us to easily display a potentially larger amount of information using text box scrollbars if necessary. In addition to displaying the question, the application gives the user two options for answering it. Users can choose a Challenge Me! option if they believe they know the answer or a Can't Think of It option if they want more hints; the two choices can also have different game-scoring possibilities. To keep things simple in the sample code, our implementation treats both of these choices the same and moves them to the next state regardless of what they choose; you may choose to add code to differentiate the choices or just remove one of the buttons if you choose not to. Our mobile application implementation has chosen to present these options using Button controls, but as above this need not necessarily be the case; radio buttons or a list box could just as easily be used to display the options if either metaphor were more appropriate for the device we are targeting. The right user interface metaphor depends on the nature of the application as well as the kind of device it is running on.

Present the user with the multiple-choice answers
In this application state, our mobile device game presents the user with multiple-choice options to answer the question. For the Pocket PC user interface, we have again chosen to use Button controls; for a smart phone interface, a numbered list box would probably be most appropriate. In this state, we have also chosen to dynamically reduce the size of the TextBox control to fit all of the button choices onto the screen. Users are allowed to guess answers until they get the right one. If the wrong answer is selected, we have chosen to gray-out (set the Enabled property to false) the wrong choice. Our application logic may also want to display text that explains what the incorrect word really means. Because there is little room in our reduced-sized text box for this kind of information, we may want to draw the text onto the top of the play field bitmap; this implementation is again left to the reader.

Present users with a final assessment of their performance on the question and wait for them to request the next question
This application state allows the game the opportunity to review users' choices with them and reinforce their learning. Because the vocabulary question is complete, we no longer need to display the question or have space dedicated to allowing the user to select multiple-choice answers. Because of this, the application has hidden all the buttons used to display multiple-choice answers and has used the extra space to enlarge the text box area. Having a large text box area allows us ample room to display text that recaps the learning of the question. For instance, we could display all of the multiple-choice words along with their translations; we could also display an example sentence showing the use of the correct word.

Figure 13.6. User interface displayed on top of form.

[View full size image]

The code in Listing 13.1 demonstrates several useful concepts for building flexible mobile device user interfaces. When designing this user interface, I started with the idea of positioning the user interface elements above the game play field. Knowing that getting the user interface right is a matter of real-world testing and iteration, it is desirable to write the code in a centralized and abstract way so that it can easily be modified without requiring complex and scattered changes in the user interface or application logic. It is for this reason that I have chosen to place the bulk of the dynamic layout code into a state machine function called StateChangeForGameUI(). Any changes in control resizing and positioning will be driven by this code. If we need to make tweaks or even radical changes to the layout, we know all of the work happens here; this means less work tracking down complex and distributed layout logic and more robust application operation. Having the user interface layout responsibility concentrated in one function (the state machine) makes it easy to experiment with different user interface layout possibilities without destabilizing the rest of the user interface code or application logic.

Figure 13.6 and Figure 13.7 display two possible configurations for our mobile vocabulary teaching game. It is important to note that in going from one layout model to the other not only have the user interface controls been moved around on the screen but elements have also been reordered in relation to one another. In Figure 13.6, the text box is positioned and dynamically resized above the other elements on the screen. In Figure 13.7, the text box is positioned and dynamically resized below any other buttons that are on the screen. Because in both cases the text box anchors itself differently to the controls surrounding it, this requires different application logic to be run. Other control positioning and reordering would also be easily possible; because the positioning code has been cleanly abstracted and centralized into our state machine, we can run whatever user interface logic we need to in order to get the onscreen positioning as we like it. The rest of the application and user interface logic are not affected by our experimentation.

Figure 13.7. User interface displayed on bottom of form.

[View full size image]

Equally important is that we have built abstracted functions to deal with updating our user interface contents. All the user interface content-updating code is either in our state machine or in dedicated functions used for the task; no user interface content is updated directly in the event handling code for our controls. This combination of abstraction and centralization makes it easy to reconfigure our user interface to use different controls as needed. This is important not just for getting the right look and feel on any given device class, but is also useful for porting the application to different device classes. For instance, our mobile application would probably use a different set of controls for user input and output if ported to a smart phone. Because the smart phone does not have a touch screen, buttons are not the best choice for answering multiple-choice questions; a list box would be better. The code in Listing 13.1 could easily be adapted to use a list box instead of buttons for the multiple-choice inputs. Other user interface changes would also be required but because our application logic and our user interface code are well encapsulated and the interaction between application logic and user interface code is centralized in a known set of functions the porting work would not be difficult. Good encapsulation, abstraction, and centralization would allow us to provide a great user experience on another class of device much more easily than if the code were decentralized and not state machine based.

Sample Code Showing Two Different Layout Models for the Same Application


The code in Listing 13.1 belongs inside a form in a Pocket PC project. Do the following to build and run the application:


1.

Start Visual Studio .NET (2003 or later) and create a C# "Smart Device Application"

2.

Choose Pocket PC as the target platform. (A project will be created for you and Pocket PC Form designer will appear.)

3.

Add the following controls to the form. Note: Don't worry about the size or position of these controls; put them wherever it is easiest to work with them on the screen. The controls will be dynamically resized and positioned at runtime by the user interface code below.

A TextBox, rename it textBoxAskQuestion, set its MultiLine property true, and set its ReadOnly property true.

A PictureBox, rename it pictureBoxGameBoard.

A Button, rename it buttonShowAnswers_AdvancedVersion.

A Button, rename it buttonShowAnswers_SimpleVersion.

A Button, rename it buttonAskQuestion.

A Button, rename it buttonAnswer0.

A Button, rename it buttonAnswer1.

A Button, rename it buttonAnswer2.

A Button, rename it buttonAnswer3.

A Button, rename it buttonAnswer4.

A Button, rename it buttonAnswer5.

4.

Double-click a blank region of the Form designer, and in the event handler function generated and hooked up for you, enter the Form_Load code listed below.

5.

For each of the Button controls above, double-click the Button in the Form designer. In the event handler function generated and hooked up for you, enter the button<ButtonName>_Click code listed below.

6.

Enter the rest of the code listed below.

7.

Set the MinimizeBox property of the form to false. At runtime this will give the form an OK box at the top right that makes it easy to close the form and exit the application. This is very useful for repeated testing.

8.

At the top of the form's code file, as the first line in the file, enter the text #define PLAYFIELD_ON_BOTTOM.

9.

Run the application both with the #define PLAYFIELD_ON_BOTTOM conditional compile directive in place and also with it commented out (that is, //#define PLAYFIELD_ON_BOTTOM) and observe the different layout models. Try them both out on a physical device and decide which model works best in terms of user look and feel and the visibility of the play field.

10.

Try your own modifications to the layout. Possibly it makes sense to have some user interface elements above the play field and some below. Maybe some of the elements should be on top of the play field or to the right or left of it. Making modifications to the state machine code should enable you to easily test and refine these concepts.


Listing 13.1. Use of State Machine to Experiment with Two Different UI layouts



//-------------------------------------------------------------
//The state machine that drives showing hand hiding buttons
//-------------------------------------------------------------
private enum GameUIState
{
startScreen = 1,
waitForNextQuestion = 2,
waitForUserToStateKnowledge = 4,
waitForUserToAnswerMultipleChoice = 8
}
//Current state of game
private GameUIState m_GameUIState;
//============================================================
//State machine used for driving the user interface
//============================================================
private void StateChangeForGameUI(GameUIState newGameUIState)
{
m_GameUIState = newGameUIState;
switch(newGameUIState)
{
case GameUIState.startScreen:
buttonAskQuestion.Visible = true;
buttonAskQuestion.Text = "Start";
//Hide the text box
textBoxAskQuestion.Visible = false;
SetAnswerButtonVisibility(false);
SetDifficultyButtonVisibility(false);
break;
case GameUIState.waitForNextQuestion:
setQuestionText("List answer details here... \r\n" +
"Lots of space to write...\r\n"+
"Waiting for user to select next question...");
textBoxAskQuestion.Visible = true;
buttonAskQuestion.Text = "Next";
buttonAskQuestion.Visible = true;
//Make sure the button is displayed on top
buttonAskQuestion.BringToFront();
SetAnswerButtonVisibility(false);
SetDifficultyButtonVisibility(false);
#if PLAYFIELD_ON_BOTTOM //PLAYFIELD is below user controls
textBoxAskQuestion.Height = pictureBoxGameBoard.Top - 2;
#else //PLAYFIELD is above user controls
textBoxAskQuestion.Top = pictureBoxGameBoard.Top +
pictureBoxGameBoard.Height + 2;
textBoxAskQuestion.Height = this.Height -
textBoxAskQuestion.Top;
#endif
break;
case GameUIState.waitForUserToStateKnowledge:
SetTextForVocabularyQuestion();
textBoxAskQuestion.Visible = true;
buttonAskQuestion.Visible = false;
SetAnswerButtonVisibility(false);
SetDifficultyButtonVisibility(true);
#if PLAYFIELD_ON_BOTTOM //PLAYFIELD is below user controls
textBoxAskQuestion.Height =
buttonShowAnswers_AdvancedVersion.Top - 2;
#else //PLAYFIELD is above user controls
textBoxAskQuestion.Top =
buttonShowAnswers_AdvancedVersion.Top +
buttonShowAnswers_AdvancedVersion.Height + 2;
textBoxAskQuestion.Height = this.Height -
textBoxAskQuestion.Top;
#endif
break;
case GameUIState.waitForUserToAnswerMultipleChoice:
buttonAskQuestion.Visible = false;
SetDifficultyButtonVisibility(false);
//Enable the buttons so they can be clicked by the user
SetAnswerButtonEnabled(true);
SetAnswerButtonVisibility(true);
#if PLAYFIELD_ON_BOTTOM //PLAYFIELD is below user controls
textBoxAskQuestion.Height = buttonAnswer0.Top - 2;
#else //PLAYFIELD is above user controls
//Position the text box to make good use of the screen
textBoxAskQuestion.Top = buttonAnswer5.Top +
buttonAnswer5.Height + 2;
textBoxAskQuestion.Height = this.Height -
textBoxAskQuestion.Top;
#endif
break;
}
}
//=============================================================
//Sets up the static layout of our user interface.
//These are all the items whose positions will remain fixed
//The user interface state machine will make changes to other
//properties
//=============================================================
private void SetStartControlPositionAndState()
{
pictureBoxGameBoard.Width = 240;
pictureBoxGameBoard.Height = 176;
//Set the size of the multiple-choice answer buttons
const int answerButtons_dx = 117;
const int answerButtons_dy = 18;
buttonAnswer0.Width = answerButtons_dx;
buttonAnswer0.Height = answerButtons_dy;
buttonAnswer1.Size = buttonAnswer0.Size;
buttonAnswer2.Size = buttonAnswer0.Size;
buttonAnswer3.Size = buttonAnswer0.Size;
buttonAnswer4.Size = buttonAnswer0.Size;
buttonAnswer5.Size = buttonAnswer0.Size;
buttonShowAnswers_AdvancedVersion.Width = answerButtons_dx;
buttonShowAnswers_AdvancedVersion.Height = 24;
buttonShowAnswers_SimpleVersion.Size =
buttonShowAnswers_AdvancedVersion.Size;
//Pixels between adjacent buttons
const int dx_betweenButtons = 3;
const int dy_betweenButtons = 2;
const int answerbuttons_beginX = 3;
//Make a background image for our bitmap, so we can see it
//in our testing
System.Drawing.Bitmap gameBoard;
gameBoard = new System.Drawing.Bitmap(
pictureBoxGameBoard.Width, pictureBoxGameBoard.Height);
System.Drawing.Graphics gameboard_gfx;
gameboard_gfx = System.Drawing.Graphics.FromImage(gameBoard);
gameboard_gfx.Clear(System.Drawing.Color.Yellow);
System.Drawing.Pen myPen = new System.Drawing.Pen(
System.Drawing.Color.Blue);
gameboard_gfx.DrawRectangle(myPen, 2,2, gameBoard.Width-4,
gameBoard.Height-6);
myPen.Dispose();
gameboard_gfx.Dispose();
pictureBoxGameBoard.Image = gameBoard;
//Position the text box that contains the questions we ask
//as well as detailed answers to users
textBoxAskQuestion.Left = 0;
textBoxAskQuestion.Width = 240;
buttonAskQuestion.Width = 64;
buttonAskQuestion.Height = 20;
#if PLAYFIELD_ON_BOTTOM //PLAYFIELD is below user controls
const int answerbuttons_beginY = 42;
const int showanswers_beginY = 77;
//---------------------------------------------
//Set up the "Easy" or "Hard" option buttons for the game
//---------------------------------------------
buttonShowAnswers_AdvancedVersion.Top = showanswers_beginY;
buttonShowAnswers_SimpleVersion.Top = showanswers_beginY;
//---------------------------------------------
//Set up the multiple-choice answers
//---------------------------------------------
//Set the control that the others will line up based on
buttonAnswer0.Top = answerbuttons_beginY;
//Place Picture Box below the controls
pictureBoxGameBoard.Top =
(answerButtons_dy + dy_betweenButtons) * 3 +
answerbuttons_beginY;
buttonAskQuestion.Top = 0;
buttonAskQuestion.Left = 174;
textBoxAskQuestion.Top = 0;
#else //PLAYFIELD is above user controls
const int answerbuttons_beginY = 174;
//--------------------------------------------------------
//Set up the "Easy" or "Hard" option buttons for the game
//--------------------------------------------------------
buttonShowAnswers_AdvancedVersion.Top = answerbuttons_beginY;
buttonShowAnswers_SimpleVersion.Top = answerbuttons_beginY;
//---------------------------------------------
//Set up the multiple-choice answers
//---------------------------------------------
//Set the control that the others will line up based on
buttonAnswer0.Top = answerbuttons_beginY;
pictureBoxGameBoard.Top = 0;
buttonAskQuestion.Top = answerbuttons_beginY;
buttonAskQuestion.Left = 174;
#endif
buttonShowAnswers_AdvancedVersion.Left = answerbuttons_beginX;
buttonShowAnswers_SimpleVersion.Left =
buttonShowAnswers_AdvancedVersion.Left +
answerButtons_dx + dx_betweenButtons;
pictureBoxGameBoard.Left = 0;
pictureBoxGameBoard.Width = 240;
pictureBoxGameBoard.Height = 172;
buttonAnswer0.Left = answerbuttons_beginX;
buttonAnswer1.Left = buttonAnswer0.Left + answerButtons_dx +
dx_betweenButtons;
buttonAnswer1.Top = buttonAnswer0.Top;
//next row
buttonAnswer2.Left = buttonAnswer0.Left;
buttonAnswer2.Top = buttonAnswer0.Top + answerButtons_dy +
dy_betweenButtons;
buttonAnswer3.Left = buttonAnswer2.Left + answerButtons_dx +
dx_betweenButtons;
buttonAnswer3.Top = buttonAnswer2.Top;
//next row
buttonAnswer4.Left = buttonAnswer2.Left;
buttonAnswer4.Top = buttonAnswer2.Top + answerButtons_dy +
dy_betweenButtons;
buttonAnswer5.Left = buttonAnswer4.Left + answerButtons_dx +
dx_betweenButtons;
buttonAnswer5.Top = buttonAnswer4.Top;
}
//-------------------------------------------------------------
//A helper function that allows us to set the visibility
//state of the buttons that show vocabulary answers
//-------------------------------------------------------------
private void SetAnswerButtonVisibility(bool visibleState)
{
buttonAnswer0.Visible = visibleState;
buttonAnswer1.Visible = visibleState;
buttonAnswer2.Visible = visibleState;
buttonAnswer3.Visible = visibleState;
buttonAnswer4.Visible = visibleState;
buttonAnswer5.Visible = visibleState;
}
//-------------------------------------------------------------
//A helper function called to set the visibility state of some
//controls
//-------------------------------------------------------------
private void SetDifficultyButtonVisibility(bool visibleState)
{
buttonShowAnswers_AdvancedVersion.Visible = visibleState;
buttonShowAnswers_SimpleVersion.Visible = visibleState;
}
//-------------------------------------------------------------
//A helper function that allows us to set the visibility
//of the buttons that show vocabulary answers
//-------------------------------------------------------------
private void SetAnswerButtonEnabled(bool enabledState)
{
buttonAnswer0.Enabled = enabledState;
buttonAnswer1.Enabled = enabledState;
buttonAnswer2.Enabled = enabledState;
buttonAnswer3.Enabled = enabledState;
buttonAnswer4.Enabled = enabledState;
buttonAnswer5.Enabled = enabledState;
}
//-------------------------------------------------------------
//Sets the text in the text box and buttons necessary
//to ask a question.
//
//In a real implementation, this function would look up
//the vocabulary questions dynamically
//-------------------------------------------------------------
private void SetTextForVocabularyQuestion()
{
setQuestionText(
"What is the English word for 'der Mensch'?");
buttonAnswer0.Text = "Four";
buttonAnswer1.Text = "Person";
buttonAnswer2.Text = "Three";
buttonAnswer3.Text = "To Jump";
buttonAnswer4.Text = "Newspaper";
buttonAnswer5.Text = "Brother";
}
//Called to evaluate a user selected a multiple-choice answer
private void evaluateMultipleChoiceAnswer(Button buttonClicked,
int selection)
{
//Note: In the nonprototype implementation, the correct
//answer would be a dynamic value, not always "button #1"
//If the user did not select the correct answer, disable
//the button they pressed
if(selection != 1)
{
//The answer selected was not the correct one
buttonClicked.Enabled = false;
}
else
{
//They got the right answer, move on with the game
StateChangeForGameUI(GameUIState.waitForNextQuestion);
}
}
//Abstracts setting the question text
void setQuestionText(string textIn)
{ textBoxAskQuestion.Text = textIn; }
//-------------------------------------------------------------
//EVENT HANDLER: User wants to see next question
//-------------------------------------------------------------
private void buttonAskQuestion_Click(object sender,
System.EventArgs e)
{
SetTextForVocabularyQuestion();
StateChangeForGameUI(GameUIState.waitForUserToStateKnowledge);
}
//-------------------------------------------------------------
//EVENT HANDLER:
//User wants to answer the question displayed and what's
//the hardest list of options possible to challenge him/her
//-------------------------------------------------------------
private void buttonShowAnswers_AdvancedVersion_Click(
object sender, System.EventArgs e)
{
//Set the state of the game to show the multiple-choice
//options
StateChangeForGameUI(
GameUIState.waitForUserToAnswerMultipleChoice);
}
//-------------------------------------------------------------
//EVENT HANDLER:
//User wants to answer the question displayed and what's
//the simplest list of options possible to challenge him/her
//-------------------------------------------------------------
private void buttonShowAnswers_SimpleVersion_Click(
object sender, System.EventArgs e)
{
//Set the state of the game to show the multiple-choice
//options
StateChangeForGameUI(
GameUIState.waitForUserToAnswerMultipleChoice);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer0_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer0, 0);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer1_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer1, 1);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer2_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer2, 2);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer3_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer3, 3);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer4_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer4, 4);
}
//EVENT HANDLER: A multiple-choice answer button was clicked
private void buttonAnswer5_Click(
object sender, System.EventArgs e)
{
evaluateMultipleChoiceAnswer(buttonAnswer5, 5);
}
//-------------------------------------------------------------
//EVENT HANDLER: Called when form is loaded
//-------------------------------------------------------------
private void Form1_Load(object sender, System.EventArgs e)
{
//Set the static properties of our visual interface
SetStartControlPositionAndState();
//Set the dynamic properties based on the state we're entering
StateChangeForGameUI(GameUIState.startScreen);
}

Layout of Controls


For mobile device applications, the layout of the user interface is important both for ease of use by the end user as well as to allow your application to present all the information that it needs to. It is almost never a good idea to take a desktop user interface and bring it down to a mobile device; I have never seen this work in practice. The screen resolution and usage model of a desktop application is radically different from that of a mobile device, and trying to cram a desktop user interface and application usage model into a device form factor is a recipe for failure. At best you will end up with a mediocre and awkward application. A far better approach is to consider, prioritize, and explicitly list the desktop scenarios that will need to be able to be performed on a mobile device along with the unique mobility scenarios you want to enable and then build an application user interface that specifically meets these needs. The same holds true for taking a mobile device application that runs on one form factor and bringing it to another; rarely does it make sense to bring over the user interface verbatim. Even if most of the application logic can be brought over unchanged, it is worth explicitly listing the key scenarios and the device-specific usage models and then designing the user interface from the ground up to meet these needs.

Real Estate Is Expensive


The smaller the device screen, the more attention must be paid to its efficient usage. Good screen real estate management is not about figuring out how to cram as many controls onto a mobile device screen as possible at any given time; almost the opposite in fact.

Mobile device real estate is limited enough that you could not fit most of the typical controls in a desktop application onto a mobile device screen even if you reduced the fonts to a minimum, shrunk down the controls as small as they could go, and lined them up as tightly as possible as if your user interface layout were a game of Tetris. Clearly, a different approach is required. The best mobile device interfaces are not busy with detail on the screen, they are sparse and elegant; paradoxically, they look as if they have room to spare. Instead of thinking about how to fit all the controls onto the mobile device's screen at once, it is worthwhile to approach the problem from the other direction and ask, "What is the absolute minimum information and controls that need to be on the screen to enable the user to take the next step?" Consider the following questions when designing the layout of your mobile device application's user interface:

What is the minimum set of information that needs to be displayed and the minimum set of controls required for navigation?
Can this set be reduced further by splitting the present screen into two or more smaller user interface states that can be displayed separately?

When moving from one user interface state to another should controls be resized?
Often times it can be desirable to shrink or grow the size of a user interface element to show or hide more detailed information as screen real estate allows.

Would a custom control be a more efficient way to display the information now being shown by several controls?
This decision must be weighed carefully. Creating a purpose-specific custom control can be a good way to efficiently use user interface real estate but must be weighed against two balancing factors: (1) The development cost of creating a custom control is much higher than that of using preexisting, pretested, controls, and (2) the usability issues of creating a new user interface metaphor. The end user already knows how to use the existing controls and will have to learn any new visual concepts you introduce. Still, in some cases the work is justified and can yield impressive results.


Location, Location, Location


Not all screen areas are equal. Placing controls in the top, bottom, left, right, or middle of your mobile device screen will result in different usability characteristics. These usability characteristics often vary from device class to device class. For example, Pocket PC controls that take text input should be placed at the top of the screen because there is a pop-up software keyboard called a SIP (software input panel) that is shown at the bottom of the screen to enable text entry. Two things should govern the location of the controls you place onto your user interface:

The style and usage guidelines for the mobile device you are targeting
Most programmable mobile devices have style guidelines for layout of user interface. These are important both to ensure that your application behaves well with the input methods present on the device (for example, buttons, touch screen, pop-up keyboard) as well as to ensure that users get a consistent look and feel between applications they are using. If you have not read the style guidelines for the device you are targeting, it is highly worth giving them a read through. This information is far better than any generic layout advice that could be given. Note: The fact that different device classes have different style guidelines is another reason why "write once, run anywhere" models tend to fail. It is just too difficult a problem to build a single user interface framework that correctly and automatically adapts to different devices style guidelines.

Usability testing on real devices
The final arbiter of your user interface's usability is a real user using it on a real device (that is, not an emulator). Because mobile devices are used in handheld situations such as outdoors, on trains, in airplanes, or in crowded elevators, there is simply no substitute for testing out the application on the real physical hardware it is going to be running on and in realistic environments.

Pick the Right Controls for the Right Devices


Along with following the correct style and layout guidelines for a given mobile device, it is important to choose the correct set of user controls for the devices you are targeting. A mobile runtime framework may support a range of user interface controls. Only some of these are appropriate for use on any given mobile device. For example, because smart phones do not have touch screens or mouse pointers for random-access navigation controls such as tab views, generic buttons and radio buttons are not particularly useful user interface metaphors for these devices. Instead list boxes and menus are far more appropriate controls for use on smart phones. In general, the smaller the device, the more specific are the requirements for controls that can be used.

When to use Different Forms and When to Swap Controls Around


There are two ways to facilitate navigation in your user interface: (1) Bring up new forms in response to user actions, and (2) show and hide controls on a single form. Both of these are mechanisms for showing a new screen full of information to the user.

There is nothing wrong with storing and managing multiple screens' worth of information in a single form and showing and hiding controls as needed. You should keep multiple screens' worth of user interface on one form if they represent related concepts and you may want to tune the relationships between them. Moving information from one "screen" to another is easier to do if they are managed in the same class.

You should separate functionality into different forms if the functionality is truly separate and there is little chance that you will want to swap the user interface elements between the two forms as you tune your user interface. This eliminates unnecessary clutter.

If your target mobile device has a large enough screen, tab controls are a middle case that allows you an in-between compromise. Usually each tab in a tab control should be thought of conceptually as a different form. The great advantage of using a tab control is that you do not have to do the showing and hiding of each screen of information manually; it is handled by the framework. Consider placing the event handling code for each tab's contents into separate class. This will give you a nice encapsulation that keeps your code from getting too messy.


/ 159