講義

71
Rung-Hung Gau Department of Computer Science and Engineering National Sun Yat- Sen University Kaohsiung, Taiwan 1 Selection Widgets

Transcript of 講義

Page 1: 講義

Rung-Hung GauDepartment of

Computer Science and Engineering

National Sun Yat-Sen University

Kaohsiung, Taiwan

1

Selection Widgets

Page 2: 講義

Outline

2

Design Pattern (MVC and MVA)AdapterSelection WidgetListBox SpinControlGridViewAutoCompleteTextView

Page 3: 講義

Design Patterns

3

Designing reusable object-oriented software is challenging.

Design patterns solve specific design problems and make object-oriented designs more flexible, elegant, and ultimately reusable.

Page 4: 講義

Design Patterns

4

Model-View-Controller (MVC) is a classic design pattern often used by applications that need the ability to maintain multiple views of the same data.

The MVC pattern hinges on a clean separation of objects into one of three categories — models for maintaining data, views for displaying all or a portion of the

data, and controllers for handling events that affect the

model or view(s).

Page 5: 講義

Design Patterns

5

Because of this separation, multiple views and controllers can interface with the same model.

Even new types of views and controllers that never existed before can interface with a model without forcing a change in the model design.

Page 6: 講義

6

Page 7: 講義

Model-View-Controller

7

Events typically cause a controller to change a model, or view, or both.

Whenever a controller changes a model’s data or properties, all dependent views are automatically updated.

Similarly, whenever a controller changes a view (for example, by revealing areas that were previously hidden), the view gets data from the underlying model to refresh itself.

Page 8: 講義

8

Page 9: 講義

MVC control flow

9

Though MVC comes in different flavors, control flow is generally as follows:The user interacts with the user interface in

some way (for example, presses a mouse button).

The controller handles the input event from the user interface, often via a registered handler or callback.

The controller notifies the model of the user action, possibly resulting in a change in the model's state. (for example, the controller updates the user's shopping cart).

Page 10: 講義

MVC control flow

10

A view uses the model indirectly to generate an appropriate user interface (for example, the view lists the shopping cart's contents). The view gets its own data from the model. The model and controller have no direct knowledge of the view.

The user interface waits for further user interactions, which restarts the cycle.

Page 11: 講義

MVC Support in Java/Swing

11

Java Swing is different from the other frameworks in that it supports two MVC patterns:

ModelFrame level model—Like other frameworks,

the design of the real model is usually left to the developer.

Control level model—Swing also supports models on the level of controls (elements of the graphical user interface). Unlike other frameworks, Swing exposes the internal storage of each control as a model.

Page 12: 講義

MVC Support in Java/Swing

12

View: The view is represented by a class that inherits from Component.

Controller: Java Swing doesn't use a single controller. Because its event model is based on interfaces, it is common to create an anonymous action class for each event. In fact, the real controller is in a separate thread, the Event dispatching thread. It catches and propagates the events to the view and model.

Page 13: 講義

Adapter

13

Adapters are bridging classes that bind data to user-interface Views

The adapter is responsible for creating the child views used to represent each item and providing access to the underlying data

(MVC pattern vs. MVA pattern) (a solid line means using methods)(a dashed line means being listener)

Page 14: 講義

14

Page 15: 講義

15

Page 16: 講義

Adapter and OOP

16

User-interface controls that support Adapter binding must extend the AdapterView abstract class.

Abstract classes are classes for which the programmer never intends to instantiate objects. (using keyword “abstract”)

Abstract classes are used only as superclasses in inheritance hierarchies and are also called abstract superclasses.

An interface describes a set of methods that can be called on an object, but does not provide concrete implementation.

Page 17: 講義

Adapter

17

In Android's case, adapters provide a common interface to the data model behind a selection-style widget, such as a listbox.

Android's adapters are responsible for providing the roster of data for a

selection widget converting individual elements of data

into specific views to be displayed inside the selection widget.

Page 18: 講義

Adapter

18

The latter facet of the adapter system is not that different from other GUI toolkits' ways of overriding default display behavior.

For example, in Java/Swing, if you want a JList-backed listbox to actually be a checklist (where individual rows are a checkbox plus label, and clicks adjust the state of the checkbox), you inevitably wind up calling setCellRenderer() to supply your own ListCellRenderer, which in turn converts strings for the list into JCheckBox-plus-JLabel composite widgets.

Page 19: 講義

Array Adapter

19

The easiest adapter to use is ArrayAdapter – all you need to do is wrap one of these around a Java array or java.util.List instance, and you have a fullyfunctioning adapter:

Page 20: 講義

20

private ArrayAdapter aa;private ListView myListView;@overridepublic void onCreate(Bundle icicle) {… String[] items={"this", "is", "a", "really", "silly", "list"}; /* The Adapter—Model binding. Converting individual elements of

data into specific views (android.R.layout.simple_list_item_1) to be displayed inside the View object that attaches to the adapter */

aa=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items); /* The Adapter—View binding. Attaching the View object to the

adapter */ myListView.setAdapter(aa);…}

Page 21: 講義

Array Adapter

21

The ArrayAdapter constructor takes three parameters:The Context to use (typically this will

be your activity instance)The resource ID of a view to use (such

as a built-in system resource ID, as shown above or a customized view)

The actual array or list of items to show

Page 22: 講義

Array Adapter

22

By default, the ArrayAdapter will invoke toString() on the objects in the list and wrap each of those strings in the view designated by the supplied resource.

android.R.layout.simple_list_item_1 simply turns those strings into TextView objects.

You can use the View.setAdapter(aa) method to attach the View (e.g., a ListView object) to the ArrayAdapter “aa”.

Those TextView widgets will be shown in the View (e.g., the ListView object) that attaches to the ArrayAdapter.

Page 23: 講義

Customized Views

23

A customized view can be created by inheriting the View super-class and overriding the onDraw() method.

Page 24: 講義

A customized view

24

<?xml version=“1.0” encoding=“utf-8”?><edu.xyz.todolist.TodoListItemViewxmlns:android=http://

schemas.android.com/apk/res/android android:layout_width=“fill_parent” android:layout_height=“fill_parent” …/>

Page 25: 講義

A customized view

25

Package edu.xyz.todolist;import …public class TodoListItemView extend TextView

{… /* override the onDraw() method to customize your own

View */

public void onDraw(Canvas canvas) { canvas.drawColor(paperColor); … super.onDraw(canvas); canvas.restore(); }}

Page 26: 講義

Other Key Adapters

26

Here are some other adapters in Android that you will likely useCursorAdapter converts a Cursor, typically

from a content provider (similar to a database), into something that can be displayed in a selection view

SimpleAdapter converts data found in XML resources

Page 27: 講義

ListBox Widget and ListActivity

27

The classic listbox widget in Android is known as ListView, which can be created as follows: include one of these in your layout, invoke setAdapter() to supply your

data and child views, attach a listener via

setOnItemSelectedListener() to find out when the selection has changed.

Page 28: 講義

ListBox Widget and ListActivity

28

However, if your activity is dominated by a single list, you might well consider creating your activity as a subclass of ListActivity, rather than the regular Activity base class. (so that the program is shorter)

If your main view is just the list, you do not even need to supply a layout – ListActivity will construct a full-screen list for you.

If you do want to customize the layout, you can, so long as you identify your ListView as @android:id/list, so ListActivity knows which widget is the main list for the activity.

Page 29: 講義

ListBox Widget and ListActivity

29

The following example is just a list with a label on top to show the current selection.

Page 30: 講義

30

Page 31: 講義

31

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://

schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/selection" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <ListView android:id="@android:id/list"

Page 32: 講義

32

android:layout_width="fill_parent" android:layout_height="fill_parent" android:drawSelectorOnTop="false" /></LinearLayout>

Page 33: 講義

33

public class ListViewDemo extends ListActivity { TextView selection; String[] items={"lorem", "ipsum", "dolor", "sit",

"amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Override public void onCreate(Bundle icicle) { /* the Bundle is a handle to the stored state of the

activity */ super.onCreate(icicle); /* provide a View for the activity */ setContentView(R.layout.main);

Page 34: 講義

34

/* create an ArrayAdapter and then attach the ListActivity (containing a View) to the ArrayAdapter */

setListAdapter(new ArrayAdapter<String>(this,

android.R.layout.simple_list_item_1, items));/* The following code is similar to DOM in web

programming. We get a component (TextView) in the layout tree via its ID */

selection=(TextView)findViewById(R.id.selection);

}

public void onListItemClick(ListView parent, View v, int position, long id) {

selection.setText(items[position]); }}

Page 35: 講義

Spin Control

35

In Android, the Spinner is the equivalent of the drop-down selector you might find in other toolkits (e.g., JComboBox in Java/Swing).

Pressing the center button on the D-pad pops up a selection dialog for the user to choose an item from.

Page 36: 講義

36

Page 37: 講義

37

Page 38: 講義

Spin Control

38

As with ListView, you provide the adapter for data and child views via setAdapter() and hook in a listener object for selections via setOnItemSelectedListener().

If you want to tailor the view used when displaying the drop-down perspective, you need to configure the adapter, not the Spinner widget.

Use the setDropDownViewResource() method to supply the resource ID of the view to use.

Page 39: 講義

Spin Control

39

The following is the same view as shown in the previous section, just with a Spinner instead of a ListView.

The Spinner property android:drawSelectorOnTop controls whether the arrows are drawn on the selector button on the right side of the Spinner UI.

Page 40: 講義

40

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://

schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/selection" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Spinner android:id="@+id/spinner“

Page 41: 講義

41

android:layout_width="fill_parent" android:layout_height="wrap_content" android:drawSelectorOnTop="true" /></LinearLayout>

Page 42: 講義

42

public class SpinnerDemo extends Activity implements AdapterView.OnItemSelectedListener

{ TextView selection; String[] items={"lorem", "ipsum", "dolor", "sit",

"amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Overridepublic void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

Page 43: 講義

43

selection=(TextView)findViewById(R.id.selection);

Spinner spin=(Spinner)findViewById(R.id.spinner);

spin.setOnItemSelectedListener(this); ArrayAdapter<String> aa=new

ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, items);

aa.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item); spin.setAdapter(aa);}

public void onItemSelected(AdapterView<?> parent,

View v, int position, long id) {

Page 44: 講義

44

selection.setText(items[position]);}

public void onNothingSelected(AdapterView<?> parent) {

selection.setText("");}

}

Page 45: 講義

Dissecting the Program

45

We attach the activity itself as the selection listener (spin.setOnItemSelectedListener(this)).

This works because the activity implements the OnItemSelectedListener interface.

We configure the adapter not only with the list of fake words, but also with a specific resource to use for the drop-down view (via aa.setDropDownViewResource()).

Also note the use of android.R.layout.simple_spinner_item as the built-in View for showing items in the spinner itself.

Finally, we implement the callbacks required by OnItemSelectedListener to adjust the selection label based on user input.

Page 46: 講義

GridView

46

GridView gives you a two-dimensional grid of items to choose from.

The GridView works much like any other selection widget use setAdapter() to provide the data and

child views, invoke setOnItemSelectedListener() to

register a selection listener, etc.

Page 47: 講義

47

Page 48: 講義

48

Page 49: 講義

49

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://

schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/selection" android:layout_width="fill_parent" android:layout_height="wrap_content" />

Page 50: 講義

50

<GridView android:id="@+id/grid" android:layout_width="fill_parent" android:layout_height="fill_parent" android:verticalSpacing="35px" android:horizontalSpacing="5px" android:numColumns="auto_fit" android:columnWidth="100px" android:stretchMode="columnWidth" android:gravity="center" /></LinearLayout>

Page 51: 講義

A Quick Review of Generics

51

Generic methods and generic classes enable programmers to specifyWith a single method declaration, a set of related

methodsEx. public static <E> void printArray(E[] inputArray);

With a single class declaration, a set of related classesEx. public class Stack<E>

Generics also provide compile-time type safety that allows programmers to catch invalid types at compile time

A wildcard type argument is denoted by a question mark (?), which by itself represents an “unknown type”.

Page 52: 講義

52

public class GridDemo extends Activity implements AdapterView.OnItemSelectedListener { TextView selection; String[] items={"lorem", "ipsum", "dolor", "sit",

"amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

selection=(TextView)findViewById(R.id.selection);

Page 53: 講義

53

GridView g=(GridView) findViewById(R.id.grid);

g.setAdapter(new FunnyLookingAdapter(this,

android.R.layout.simple_list_item_1, items)); g.setOnItemSelectedListener(this);}

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {

selection.setText(items[position]); } public void

onNothingSelected(AdapterView<?> parent) {

selection.setText(""); }

Page 54: 講義

54

private class FunnyLookingAdapter extends ArrayAdapter {

Context ctxt; FunnyLookingAdapter(Context ctxt, int

resource, String[] items) { super(ctxt, resource, items); this.ctxt=ctxt; }

public View getView(int position, View convertView, ViewGroup parent) {

TextView label=(TextView)convertView; if (convertView==null) { convertView=new TextView(ctxt); label=(TextView)convertView;

Page 55: 講義

55

} label.setText(items[position]); return(convertView); } }}

Page 56: 講義

Dissecting the Program

56

For the grid cells, rather than using auto-generated TextView widgets as in the previous sections, we create our own views, by subclassing ArrayAdapter and overriding getView().

Page 57: 講義

public abstract View getView (int position, View convertView, ViewGroup parent)

57

Get a View that displays the data at the specified position in the data set.

You can either create a View manually or inflate it from an XML layout file.

When the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use inflate(int, android.view.ViewGroup, boolean) to specify a root view and to prevent attachment to the root.

Page 58: 講義

public abstract View getView (int position, View convertView, ViewGroup parent)

58

ParametersPosition: The position of the item within the

adapter's data set of the item whose view we want.

convertView: The old view to reuse, if possible. Note: You should check that this view is non-null and of

an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.

parent: The parent (GridView, ListView, and etc.) that this view will eventually be attached to

ReturnsA View corresponding to the data at the specified

position.

Page 59: 講義

AutoCompleteTextView

59

The AutoCompleteTextView is sort of a hybrid between the EditText (field) and the Spinner.

With auto-completion, as the user types, the text is treated as a prefix filter, comparing the entered text as a prefix against a list of candidates.

Matches are shown in a selection list that folds down from the field.

The user can either type out an entry or choose an entry from the list to be the value of the field.

Page 60: 講義

60

Page 61: 講義

61

Page 62: 講義

62

Page 63: 講義

AutoCompleteTextView

63

AutoCompleteTextView subclasses EditText, so you can configure all the standard look-and-feel aspects, such as font face and color.

In addition, AutoCompleteTextView has a android:completionThreshold property, to indicate the minimum number of characters a user must enter before the list filtering begins.

You can give AutoCompleteTextView an adapter containing the list of candidate values via setAdapter().

Page 64: 講義

AutoCompleteTextView

64

Since the user could type something not in the list, autoCompleteTextView does not support selection listeners.

You can register a TextWatcher to be notified when the text changes.

These events will occur either because of manual typing or from a selection from the drop-down list.

Page 65: 講義

65

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://

schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/selection" android:layout_width="fill_parent" android:layout_height="wrap_content" />

Page 66: 講義

66

<AutoCompleteTextView android:id="@+id/edit"

android:layout_width="fill_parent" android:layout_height="wrap_content" android:completionThreshold="3"/></LinearLayout>

Page 67: 講義

67

public class AutoCompleteDemo extends Activity implements TextWatcher { TextView selection; AutoCompleteTextView edit; String[] items={"lorem", "ipsum", "dolor", "sit",

"amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue",

"purus"};

@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main);

Page 68: 講義

68

selection=(TextView)findViewById(R.id.selection);

edit=(AutoCompleteTextView)findViewById(R.id.edit);

edit.addTextChangedListener(this); edit.setAdapter(new

ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,

items)); }

public void onTextChanged(CharSequence s, int start, int before, int count) {

selection.setText(edit.getText()); }

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

Page 69: 講義

69

// needed for interface, but not used }

public void afterTextChanged(Editable s) {

// needed for interface, but not used }

}

Page 70: 講義

Dissecting the Program

70

The activity implements TextWatcher, which means our callbacks are onTextChanged() and beforeTextChanged().

In this case, we are only interested in the former, and we update the selection label to match the AutoCompleteTextView's current contents.

Page 71: 講義

References

71

http://developer.android.com/reference/packages.html

Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns, Elements of Reusable Object-Oriented Siftware, 1995, Addison-Wesley Inc., USA.

Reto Meier, Professional Android Application Development, 2009, Wrox Inc., USA.

Mark L. Murphy, The Busy Coder's Guide to Android Development, 2009, CommonsWare, LLC, USA.