Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition11.1. Android ViewsThe Views in the following section are the meat and potatoes of your
application; essential widgets that you'll use over and over and that your
users will be familiar with from other applications. 11.1.1. TextView and EditTextA TextView, as shown in the line "This is some text" in Figure 11-1, is just what you'd expect: a
place to display a text string. The vanilla TextView is for display
only, whereas EditText is a predefined subclass of TextView that
includes rich editing capabilities. 
Each TextView has the attributes you'd expect of such a component:
you can change its height, width, font, text color, background color,
and so forth. TextViews also have some useful unique attributes:
autoLink If set (true), finds URLs in the displayed text and automatically
converts them to clickable links.
autoText If set (true), finds and corrects simple spelling errors in the
text.
editable If set (true), indicates that the program has defined an input method to
receive input text (default is false for TextView, and true for
EditText).
inputMethod Identifies the input method (EditText defines one for generic
text).
Example 11-1 shows how
to use a TextView and an EditText with Buttons. (Buttons are covered in
the next section.) It also shows the XML layout file (main.xml), which uses pretty standard and
recommended layout parameters. Example 11-1. Layout file for TextView and EditView example<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/txtDemo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<EditText
android:id="@+id/eTxtDemo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/btnDone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Log it"
/>
</LinearLayout>
|
Example 11-2 contains the
accompanying Java source (TextViewDemo.java). Example 11-2. Java for TextView and EditView: TextViewDemo.javapackage com.oreilly.demo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class TextViewDemo extends Activity {
private static TextView txt1;
private static EditText etxt1;
private static Button btn1;
// Create a button click listener for the Done button.
private final Button.OnClickListener btnDoneOnClick = new Button.OnClickListener() {
public void onClick(View v) {
String input = etxt1.getText().toString();
//Log the input string
Log.v("TextViewDemo", input);
etxt1.setText("");
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Get pointers to the Views defined in main.xml
txt1 = (TextView) findViewById(R.id.txtDemo);
etxt1 = (EditText) findViewById(R.id.eTxtDemo);
btn1 = (Button) findViewById(R.id.btnDone);
//Set the string displayed in TextView1
txt1.setText("This is some text.");
//Set the OnClickListener for the Done button
btn1.setOnClickListener(btnDoneOnClick);
}
} |
Here are some of the highlights of the code: Now the user can enter and edit text in the EditText, and when he
clicks on "Log it", the OnClickListener is called and
the text is written to the logcat log. The string in the EditText is
cleared out, and the widget is ready for another entry. 11.1.2. Button and ImageButtonThe Button View is just a button, printed with some text to identify
it, that the user can click to invoke some action. The previous section
created a Button and connected it to an OnClickListener
method that executes when the Button is clicked. Android has a very visual, mobile-oriented user interface, so you
might want to use a button with an image on it rather than one with
text. Android provides the ImageButton View for just that purpose. You
can adapt Example 11-2 to use an
ImageButton by making one change in the XML file and another in the Java
code: In main.xml, replace the
Button definition for btnDone
with an ImageButton: ...
<ImageButton
android:id="@+id/btnDone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
... In TextViewDemo.java,
redefine btn1 as an ImageButton
and add a line to set the image to a PNG image in the drawable directory: ...
private static ImageButton btn1;
...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Get pointers to the Views defined in main.xml
txt1 = (TextView) findViewById(R.id.txtDemo);
etxt1 = (EditText) findViewById(R.id.eTxtDemo);
btn1 = (ImageButton) findViewById(R.id.btnDone);
...
//Set the image for the Done button
btn1.setImageResource(R.drawable.log);
...
The button now appears as shown in Figure 11-2. 
11.1.3. Adapters and AdapterViewsAdapters and AdapterViews
are an important and useful basis for several of the views
discussed in the rest of this chapter. Using extensions to these
classes, you can address an extremely wide variety of situations. The AdapterView is a generic, list-oriented
view of data. Any collection of data objects that can be ordered in some
relatively stable way can be displayed through an AdapterView. An
AdapterView is always associated with an
Adapter, which acts as the bridge between it and the
underlying data collection. The Adapter has two
responsibilities: At the request of the AdapterView, the
Adapter must be able to find the data object that
corresponds to a particular index. It must, in other words, be able
to find the data object that is visible in the
AdapterView at a particular location. Inversely, the Adapter must be able to
supply a view through which the data at a particular index can be
displayed.
It takes only a moment's reflection to understand how the
AdapterView works: It is a
ViewGroup that contains all the machinery necessary
to serve as both the View and Controller for a collection of generic
widgets. It can lay them out on the display, pass in clicks and
keystrokes, and so on. It need never concern itself with what the
subviews actually display; it distinguishes them only by their indexes.
Whenever it needs to perform either of the two operations that are not
entirely generic—creating a new view or getting the data object attached
to a particular view—it relies on the Adapter to
convert an index into either a data object or the view of a data
object. The AdapterView requests new views from an
implementation of the Adapter interface, as it needs
them, for display. For instance, as a user scrolls though a list of
contacts, the AdapterView requests a new view for
each new contact that becomes visible. As an optimization, the
AdapterView may offer a view that is no longer
visible (in this case, one that has scrolled off the display) for reuse.
This can dramatically reduce memory churn and speed up display. When offered a recycled view, however, the
Adapter must verify that it is the right kind of view
through which to display the data object at the requested index. This is
necessary because the Adapter is not limited to
returning instances of a single view class in response to the request
for a view. If the Adapter represents several kinds
of objects, it might create several different types of views, each
applicable to some subset of the data objects in the collection. A list
of contacts, for instance, might have two entirely different view
classes: one for displaying acquaintances that are currently online and
another for those who are not. The latter might completely ignore
clicks, whereas the former would open a new chat session when
clicked. Although AdapterView and
Adapter are both abstract and cannot be directly
instantiated, the UI toolkit includes several prebuilt
Adapters and AdapterViews that can
be used unmodified or further subclassed to provide your own
customizations. ListAdapter and SpinnerAdapter are
particularly useful Adapters, while
ListView, GridView, Spinner, and
Gallery are all handy subclasses of
AdapterView. If you plan to create your own subclass
of AdapterView, a quick look at the code for one of
these classes will get you off to a running start. A good example of the use of an AdapterView can
be found in Section 11.2.1. The
Gallery view in that section is a subclass of
AdapterView, and uses a subclass of
Adapter called
ImageAdapter. 11.1.4. CheckBoxes, RadioButtons, and SpinnersThe Views we present in this section are probably familiar to
you from other user interfaces. Their purpose is to allow the user to
choose from multiple options. CheckBoxes are typically used when you
want to offer multiple selections with a yes/no or true/false choice for
each. RadioButtons are used when only one choice is allowed at a
time. Spinners are similar to combo boxes in some frameworks. A combo
box typically displays the currently selected option, along with a
pull-down list from which the user can click on another option to select
it. Android has adapted these familiar components to make them more
useful in a touchscreen environment. Figure 11-3 shows the three types
of multiple-choice Views laid out on an Android application, with the
Spinner pulled down to show the options. 
The layout XML file that created the screen in the figure looks
like this: <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<CheckBox
android:id="@+id/cbxBox1"
android:layout_width="20dp"
android:layout_height="20dp"
android:checked="false"
/>
<TextView
android:id="@+id/txtCheckBox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="CheckBox: Not checked"
/>
<RadioGroup
android:id="@+id/rgGroup1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/RB1" android:text="Button1" />
<RadioButton android:id="@+id/RB2" android:text="Button2" />
<RadioButton android:id="@+id/RB3" android:text="Button3" />
</RadioGroup>
<TextView
android:id="@+id/txtRadio"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="RadioGroup: Nothing picked"
/>
<Spinner
android:id="@+id/spnMusketeers"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="2dp"
/>
</LinearLayout>
The file just lists each View we want on the screen along with the
attributes we want. A RadioGroup is really a ViewGroup, so it contains
the appropriate RadioButton Views. Example 11-3 shows the Java file that
responds to user clicks. Example 11-3. Java for CheckBox, RadioButtons, and Spinnerpackage com.oreilly.select;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.google.android.maps.GeoPoint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
public class SelectExample extends Activity {
private CheckBox checkBox;
private TextView txtCheckBox, txtRadio;
private RadioButton rb1, rb2, rb3;
private Spinner spnMusketeers;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
checkBox = (CheckBox) findViewById(R.id.cbxBox1);
txtCheckBox = (TextView) findViewById(R.id.txtCheckBox);
txtRadio = (TextView) findViewById(R.id.txtRadio);
rb1 = (RadioButton) findViewById(R.id.RB1);
rb2 = (RadioButton) findViewById(R.id.RB2);
rb3 = (RadioButton) findViewById(R.id.RB3);
spnMusketeers = (Spinner) findViewById(R.id.spnMusketeers);
// React to events from the CheckBox
checkBox.setOnClickListener(new CheckBox.OnClickListener() {
public void onClick(View v){
if (checkBox.isChecked()) {
txtCheckBox.setText("CheckBox: Box is checked");
}
else
{
txtCheckBox.setText("CheckBox: Not checked");
}
}
});
// React to events from the RadioGroup
rb1.setOnClickListener(new RadioGroup.OnClickListener() {
public void onClick(View v){
txtRadio.setText("Radio: Button 1 picked");
}
});
rb2.setOnClickListener(new RadioGroup.OnClickListener() {
public void onClick(View v){
txtRadio.setText("Radio: Button 2 picked");
}
});
rb3.setOnClickListener(new RadioGroup.OnClickListener() {
public void onClick(View v){
txtRadio.setText("Radio: Button 3 picked");
}
});
// Set up the Spinner entries
List<String> lsMusketeers = new ArrayList<String>();
lsMusketeers.add("Athos");
lsMusketeers.add("Porthos");
lsMusketeers.add("Aramis");
ArrayAdapter<String> aspnMusketeers =
new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
lsMusketeers);
aspnMusketeers.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
spnMusketeers.setAdapter(aspnMusketeers);
// Set up a callback for the spinner
spnMusketeers.setOnItemSelectedListener(
new OnItemSelectedListener() {
public void onNothingSelected(AdapterView<?> arg0) { }
public void onItemSelected(AdapterView<?> parent, View v,
int position, long id) {
// Code that does something when the Spinner value changes
}
});
}
} |
The Views work as follows:
CheckBox The CheckBox View takes care of flipping its state back and
forth and displaying the appropriate checkmark when the state is
true. All you have to do is create an "OnClickListener" to
catch click events, and you can add whatever code you
want to react.
RadioGroup As mentioned earlier, the RadioGroup View is really a
ViewGroup that contains any number of RadioButton Views. The user
can select only one of the buttons at a time, and you capture the
selections by setting OnClickListeners for each RadioButton. Note that clicking on
one of the RadioButtons does not fire a click
event for the RadioGroup.
Spinner Spinners require the most work of these three Views, but can
also provide the best use of scarce screen real estate. As shown,
the Spinner is normally collapsed to the currently selected entry,
and when you touch the down arrow on the right, it presents a
drop-down list of the other choices. To make that happen, you
must: Create a list of the selections (which can be a dynamic
list built and changed by your application). Create an ArrayAdapter from the list that the Spinner
can use for its drop-down list. Note that the formats shown
for the ArrayAdapter (simple_spinner_item and simple_spinner_dropdown_item) are
defined by Android; they do not appear in your resource XML
files. Create an onItemSelectedListener for the Spinner to
capture select events. The
listener has to contain both an onItemSelected method and an onNothingSelected
method.
 |