Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Module 6. User Interface Design 1. Android Views, Layouts, Menus and Dialogs a) Views Definition: o In an Android application, the user interface is built using View and ViewGroup objects. There are many types of views and view groups, each of which is a descendant of the View class. o View objects are the basic units of user interface expression on the Android platform. The View class serves as the base for subclasses called "widgets," which offer fully implemented UI objects, like text fields and buttons. The ViewGroup class serves as the base for subclasses called "layouts," which offer different kinds of layout architecture, like linear, tabular and relative. o Relationship between Views and Activity An activity can contain one or more views. An activity has to have at least one view if we want to have a user interface. o A View object: is a data structure whose properties store the layout parameters and content for a specific rectangular area of the screen. handles its own measurement, layout, drawing, focus change, scrolling, and key/gesture interactions for the rectangular area of the screen in which it resides. is also a point of interaction for the user and the receiver of the interaction events. View Hierarchy o On the Android platform, you define an Activity's UI using a hierarchy of View and ViewGroup nodes, as shown in the diagram below. Figure 6.1 View Hierarchy Example. o A hierarchy tree can be built up using Android’s set of predefined widgets and layouts, or with custom Views that you create yourself. o In order to attach the view hierarchy tree to the screen for rendering, your Activity must call the setContentView() method and pass a reference to the root node object. o The root node of the hierarchy requests that its child nodes draw themselves — in turn, each view group node is responsible for calling upon each of its own child views to draw themselves. o Let’s look at an example of a Sudoku application [3] where a view is used: package org.example.sudoku; import android.app.Activity; import android.os.Bundle; public class Sudoku extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } The onCreate() method of this activity is called automatically by Android to initialize the activity. As you can see there is a call to setContentView() which fills in the contents of the activity’s screen. R.lauout.main is a resource identifier that refers to the main.xml file in the res/layout directory. This main.xml declares the user interface in XML. The R class is managed automatically by the Android. b) Layouts The most common way to define your layout and express the view hierarchy is with an XML layout file. Each element in an XML Layout is a View (or a subclass of a View, such as a Button)or ViewGroup object (or descendent thereof). View objects are leaves in the tree, ViewGroup objects are branches in the tree (see the View Hierarchy figure above). The name of an XML element is respective to the Java class that it represents. So a <TextView> element creates a TextView in your UI, and a <LinearLayout> element creates a LinearLayout view group. When you load a layout resource, the Android system initializes these run-time objects, corresponding to the elements in your layout. Let’s look at the following example which defines a simple vertical layout with a text view and a button: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout> o Notice that the LinearLayout element contains both the TextView and the Button. You can nest another LinearLayout (or other type of view group) inside here, to lengthen the view hierarchy and create a more complex layout. A layout is a container for one or more child objects and a behavior to position them on the screen within the rectangle of the parent object. Here is a list of the most common layouts provided by Android: o FrameLayout : Arranges its children so they all start at the top left of the screen. This is used for tabbed views and image switchers. o LinearLayout: Arranges its children in a single column or row. This is the most common layout you will use. o RelativeLayout: Arranges its children in relation to each other or to the parent. This is often used in forms. o TableLayout: Arranges its children in rows and columns, similar to an HTML table. Common parameters to all layouts: o xmlns:android=”http://schemas.android.com/apk/res/android” Defines the XML namespace for Android. You should define this once, in the first XML tag in the file. o android:layout_width=”fill_parent”, android:layout_height=”fill_parent” Takes up the entire width and height of the parent (in this case, the window). Possible values are fill_parent and wrap_content. Sudoku Example: o Let’s look at an example of the Sudoku application where the user interface is defined in main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/main_title" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/continue_label" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/new_game_label" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/about_label" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/exit_label" /> </LinearLayout> o Running the Sudoku application with this xml file we get the following screen shot: Figure 6.2 Sudoku Application Main Screen o The following code represents the Sudoku main.xml file which defines the user interface for our Sudoku application. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="@color/background" android:layout_height="fill_parent" android:layout_width="fill_parent" android:padding="30dip" android:orientation="horizontal"> <LinearLayout android:orientation="vertical" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_gravity="center"> <TextView android:text="@string/main_title" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_marginBottom="25dip" android:textSize="24.5sp" /> <Button android:id="@+id/continue_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/continue_label" /> <Button android:id="@+id/new_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/new_game_label" /> <Button android:id="@+id/about_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/about_label" /> <Button android:id="@+id/exit_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/exit_label" /> </LinearLayout> </LinearLayout> o As we can see the UI defined here contains a LinearLayout inside another LinearLayout. The first <LinearLayout> element defines the application settings like background color through android:background attribute, the hight and the width of the screen and so on. o The inner LinearLayout defines the layout for the buttons that will be contained here. The attribute android:orientation indicates the orientation of the elements in the screen, and we can see that the height, width and gravity are defined here. This LinearLayout contains a TextView, used as a label for the Game, showing the text: “Android Sudoku” as a title for the screen. Than we see four button elements, one for Continue, one for New Game, another one for About and finally one for Exit. o Inside the <LinearLayout> tag there exists a child widget: <TextView android:text="@string/main_title" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_marginBottom="25dip" android:textSize="24.5sp" /> which defines a simple text label. Notice that instead of hard coding the English text we are using @string/main_title syntax to refer to strings in the res/values/strings.xml file. All the text (string literals) that appears in your application needs to be specified in your resource files. This file looks like this: <resources> <string name="app_name">Sudoku</string> <string name="main_title">Android Sudoku</string> <string name="continue_label">Continue</string> <string name="new_game_label">New Game</string> <string name="about_label">About</string> <string name="exit_label">Exit</string> </resources> As you can see the @string/main_title value is Android Sudoku. o Now if we run the Sudoku application (version 2 of the Sudoku code Sudokuv2) we will get something like this: Figure 6.3 Sudoku Application The onClick method is implemented by our activity (Sudoku) and automatically called each time one of the four buttons is pressed. First step is to determine which of the buttons was pressed and based on that, act accordingly. public void onClick(View v) { switch (v.getId()) { case R.id.continue_button: startGame(Game.DIFFICULTY_CONTINUE); break; // ... case R.id.about_button: Intent i = new Intent(this, About.class); startActivity(i); break; // More buttons go here (if any) ... case R.id.new_button: openNewGameDialog(); break; case R.id.exit_button: finish(); break; } } For this to appear in the main screen of the application we need to add the view created in the xml file in the Sudoku class. In the below onCreate method behaviour is added to the application. Code was added to call findViewById() to look up an Android view given its resource ID and setOnClickListener() to tell Android which objects to tickle when the user touches or clicks the view. For the click listener to work we need to implement OnClickListener in the Sudoku Activity by adding implement OnClickListener. /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Set up click listeners for all the buttons View continueButton = this.findViewById(R.id.continue_button); continueButton.setOnClickListener(this); View newButton = this.findViewById(R.id.new_button); newButton.setOnClickListener(this); View aboutButton = this.findViewById(R.id.about_button); aboutButton.setOnClickListener(this); View exitButton = this.findViewById(R.id.exit_button); exitButton.setOnClickListener(this); } o Remember that constants like R.id.about_button are created by the Eclipse plug-in in R.java when it sees @+id/about_button in res/layout/main.xml. Let’s look at another xml file for the About Activity. This file looks like this: <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip"> <TextView android:id="@+id/about_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/about_text" /> </ScrollView> This file describes the screen About which contains a simple text given in @strings/about_text. This screen is obtained if we navigate to About button in the Sudoku application, and it looks like this: Figure 6.4 About Screen in Sudoku Application o For the above screen to appear we need to link it to the About Activity. This is done in the About class: import android.app.Activity; import android.os.Bundle; public class About extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.about); } } The link is done by calling setContentView(R.layout.about) which will look for the about.xml file in the layout subdirectory. Remember that onCreate() is automatically called by the Android platform to initialize the About Activity. o Keep in mind that every activity needs to be declared in AndroidManifest.xml. This file contains the following: <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.sudoku" android:versionCode="1" android:versionName="1.0.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Sudoku" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".About" android:label="@string/about_title" </activity> <!-- More activities can go here --> </application> </manifest> o As we can see the above file contains a reference to the icon of the application which is located in the resource directory, specifically drawable/icon. Furthermore it contains the application label as @string/app_name, and contains the activities defined in the application, in our case Sudoku, About, Settings and Game. If we want to apply a Theme we will need to add the following line: to the activity element for About, thus obtaining: android:theme="@android:style/Theme.Dialog" <activity android:name=".About" android:label="@string/about_title" android:theme="@android:style/Theme.Dialog"> </activity> Including this change to the Manifest file and running the application again, the following screen is obtained for the About screen. As you can see, now the About information is displayed as a Dialog which appears on top of the main Sudoku screen. Figure 6.5 Themed About Screen of Sudoku c) Menus Menus are an important part of any application. They provide familiar interfaces that reveal application functions and settings. Android offers an easy programming interface for developers to provide standardized application menus for various situations. Android offers three fundamental types of application menus: o Options Menu – is the primary set of menu items for an Activity. It is revealed by pressing the device MENU key. Within the Options Menu are two groups of menu items: Icon Menu – is the collection of items initially visible at the bottom of the screen at the press of the MENU key. It supports a maximum of six menu items. These are the only menu items that support icons and the only menu items that do not support checkboxes or radio buttons. Expanded Menu – is a vertical list of items exposed by the "More" menu item from the Icon Menu. It exists only when the Icon Menu becomes over-loaded and is comprised of the sixth Option Menu item and the rest. o Context Menu – is a floating list of menu items that may appear when you perform a long-press on a View (such as a list item). o Submenu – is a floating list of menu items that is revealed by an item in the Options Menu or a Context Menu. A Submenu item cannot support nested Submenus. Options Menu o The Options Menu is opened by pressing the device MENU key. o If more than six items are added to the Options Menu, then those that can't fit in the Icon Menu are revealed in the Expanded Menu, via the "More" menu item. The Expanded Menu is automatically added when there are more than six items. o Should include basic application functions and any necessary navigation items (e.g., to a home screen or application settings). You can also add Submenus for organizing topics and including extra menu functionality. o When this menu is opened for the first time, the Android system will call the Activity onCreateOptionsMenu() callback method. Before looking into how to override this method to fit our purposes, let’s look at the xml file in res/menu/menu.xml for the menu of the Sudoku application. <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/settings" android:title="@string/settings_label" android:alphabeticShortcut="@string/settings_shortcut" /> </menu> Where settings_shortcut is defined in the strings.xml file as: <string name=”settings_shortcut”>s</string> The title of the menu is specified in settings_label in strings.xml file showing “Settings…”. Figure 6.6 represents the illustration of the menu in the Sudoku application. Figure 6.6 Sudoku’s Menu o In a menu XML layout, there are three valid elements: <menu>, <group> and <item>. The item and group elements must be children of a menu, but item elements may also be the children of a group, and another menu element may be the child of an item (to create a Submenu). Of course, the root node of any file must be a menu element. o Now let’s look at how the menu is invoked in our application. We need to override the Sudoku.onCreateOptionsMenu() method, as follows: @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } getMenuInflater() returns an instance of MenuInflater that we use to read the menu definition from XML and turns it into a real view. When the user selects any menu item, onOptionsItemSelected() will be called. Here is the definition for that method: @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.settings: startActivity(new Intent(this, Settings.class)); return true; // More items go here (if any) ... } return false; } o The same menu can be obtained by creating it directly in the code using the following code: public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 0, 0, R.string.settings_label); return true; } The Settings screen obtained by pressing the button Settings from the options menu is the shown in Figure 6.7. The two options provided refer to music and hints. The first option is playing music in the background, while the second one shows hits during the play. Depending on whether the music is turned on or off, the Music class will play music in the background or not. Hints are used when drawing the board, in PuzzleView class, presented in more detail in the following module. Figure 6.7 Sudoku Settings Screen Context Menu o The Android context menu is similar, in concept, to the menu revealed with a "right-click" on a PC. When a view is registered to a context menu, performing a "long-press" (press and hold for about two seconds) on the object will reveal a floating menu that provides functions relating to that item. o can be registered to any View object, however, they are most often used for items in a ListView, which helpfully indicates the presence of the context menu by transforming the background color of the ListView item when pressed. (The items in the phone's contact list offer an example of this feature.) o Similar to the options menu, to create a context menu, you must override the Activity’s context menu callback methods: onCreateContextMenu() and onContextItemSelected(). Submenus o A sub menu can be added within any menu, except another sub menu. These are very useful when your application has a lot of functions that may be organized in topics, like the items in a PC application's menu bar (File, Edit, View, etc.). o A sub menu is created by adding it to an existing Menu with addSubMenu(). This returns a SubMenu object (an extension of Menu). You can then add additional items to this menu, with the normal routine, using the add() methods. For example: public boolean onCreateOptionsMenu(Menu menu) { boolean result = super.onCreateOptionsMenu(menu); SubMenu fileMenu = menu.addSubMenu("File"); SubMenu editMenu = menu.addSubMenu("Edit"); fileMenu.add("new"); fileMenu.add("open"); fileMenu.add("save"); editMenu.add("undo"); editMenu.add("redo"); return result; } Menu Features o Menu Groups When adding new items to a menu, you can optionally include each item in a group. A menu group is a collection of menu items that can share certain traits, like whether they are visible, enabled, or checkable. A group is defined by an integer (or a resource id, in XML). A menu item is added to the group when it is added to the menu, using one of the add() methods that accepts a groupId as an argument, such as add(int, int, int, int). You can show or hide the entire group with setGroupVisible(); enable or disable the group with setGroupEnabled(); and set whether the items can be checkable with setGroupCheckable(). o Checkable menu items Any menu item can be used as an interface for turning options on and off. This can be indicated with a checkbox for stand-alone options, or radio buttons for groups of mutually exlusive options (see the screenshot to the right). To make a single item checkable, use the setCheckable() method, like so: menu.add(0, VIBRATE_SETTING_ID, 0, "Vibrate") .setCheckable(true); This will display a checkbox with the menu item (unless it's in the Icon Menu). To make a group of mutually exclusive radio button items, simply assign the same group ID to each menu item and call setGroupCheckable(). In this case, you don't need to call setCheckable() on each menu items, because the group as a whole is set checkable. Here's an example of two mutually exclusive options in a Submenu: SubMenu subMenu = menu.addSubMenu("Color"); subMenu.add(COLOR_MENU_GROUP, COLOR_RED_ID, 0, "Red"); subMenu.add(COLOR_MENU_GROUP, COLOR_BLUE_ID, 0, "Blue"); subMenu.setGroupCheckable(COLOR_MENU_GROUP, true, true); In the setGroupCheckable() method, the first argument is the group ID that we want to set checkable. The second argument is whether we want the group items to be checkable. The last one is whether we want each item to be exclusively checkable (if we set this false, then all the items will be checkboxes instead of radio buttons). When the group is set to be exclusive (radio buttons), each time a new item is selected, all other are automatically de-selected. o Shortcut keys Quick access shortcut keys using letters and/or numbers can be added to menu items with setAlphabeticShortcut(char) (to set char shortcut), setNumericShortcut(int) (to set numeric shortcut), or setShortcut(char,int) (to set both). Case is not sensitive. For example: menu.add(0, MENU_QUIT, 0, "Quit").setAlphabeticShortcut('q'); Now, when the menu is open (or while holding the MENU key), pressing the "q" key will select this item. In XML the same result can be achieved using the following syntax: android:alphabeticShortcut="@string/settings_shortcut" like in the definition of the menu Settings presented previously and listed below. <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/settings" android:title="@string/settings_label" android:alphabeticShortcut="@string/settings_shortcut" /> </menu> d) Dialogs A dialog is usually a small window that appears in front of the current Activity. The underlying Activity loses focus and the dialog accepts all user interaction. Dialogs are normally used for notifications and short activities that directly relate to the application in progress. The Android API supports the following types of Dialog objects: o AlertDialog – a dialog that can manage zero, one, two, or three buttons, and/or a list of selectable items that can include checkboxes or radio buttons. The AlertDialog is capable of constructing most dialog user interfaces and is the suggested dialog type. o ProgressDialog – a dialog that displays a progress wheel or progress bar. Because it's an extension of the AlertDialog, it also supports buttons. o DatePickerDialog – a dialog that allows the user to select a date. o TimePickerDialog – a dialog that allows the user to select a time. A dialog is always created and displayed as a part of an Activity. You should normally create dialogs from within your Activity's onCreateDialog(int) callback method. When you use this callback, the Android system automatically manages the state of each dialog and hooks them to the Activity, effectively making it the "owner" of each dialog. As such, each dialog inherits certain properties from the Activity. When you want to show a dialog, call showDialog(int) and pass it an integer that uniquely identifies the dialog that you want to display. When a dialog is requested for the first time, Android calls onCreateDialog(int) from your Activity, which is where you should instantiate the Dialog. This callback method is passed the same ID that you passed to showDialog(int). After you create the Dialog, return the object at the end of the method. Now let’s look at our Sudoku application to see how an AlertDialog is created. When the option New Game is chosen in the menu of Sudoku, we want to pop up a dialog box asking the user to select between three difficulty levels. First we need to add a few more strings in res/values/strings.xml: <string <string <string <string name="new_game_title">Difficulty</string> name="easy_label">Easy</string> name="medium_label">Medium</string> name="hard_label">Hard</string> Now we need to create the list of difficulties as an array resource in res/values/arrays.xml: <resources> <array name="difficulty"> <item>@string/easy_label</item> <item>@string/medium_label</item> <item>@string/hard_label</item> </array> </resources> The code to create the new AlertDialog is located in openNewGameDialog() method called when the user presses on the button corresponding for New Game is listed below. Next Figure illustrates the screen displaying this alert dialog. After the user chooses a difficulty level, the onClick method of DialogOnClickListener class is being called that will actually call the last method, startGame. class DialogOnClickListener implements DialogInterface.OnClickListener{ public void onClick(DialogInterface dialoginterface, int i) { startGame(i); } } /** Ask the user what difficulty level they want */ private void openNewGameDialog() { DialogOnClickListener listener = new DialogOnClickListener(); AlertDialog.Builder alertDiag = new AlertDialog.Builder(this); alertDiag.setTitle(R.string.new_game_title); alertDiag.setItems(R.array.difficulty,listener); alertDiag.show(); } /** Start a new game with the given difficulty level */ private void startGame(int i) { Log.d(TAG, "clicked on " + i); // Start game here... } The setItems() method takes two parameters: the resource ID of the item list, in this case an array named difficulty defined in res/values/arrays.xml, and a listener that will be called when one of the items is selected. The method startGame(int i) will contain the main functionality of the game and will be presented in the next Module. Figure 6.8 Difficulty Alert Dialog Screen References: [1] [2] [3] XML Online Tutorial, http://www.w3schools.com/xml/default.asp Android Online Tutorial, http://developer.android.com/guide/index.html Ed Burnette, Hello, Android: Introducing Google’s Mobile Development Platform.