blob: 1ddd1df7fe84431500d1d73ca3393d6baac3d258 [file] [log] [blame]
page.title=Form Stuff
parent.title=Hello, Views
parent.link=index.html
@jd:body
<p>This tutorial introduces a variety of widgets that are useful when creating forms, such as
image buttons, text fields, checkboxes and radio buttons.</p>
<ol>
<li>Start a new project named <em>HelloFormStuff</em>.</li>
<li>Your <code>res/layout/main.xml</code> file should already have a basic {@link
android.widget.LinearLayout}:
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
&lt;/LinearLayout>
</pre>
<p>For each widget you want to add, just put the respective View inside this {@link
android.widget.LinearLayout}.</p>
</li>
</ol>
<p>Each section below also assumes that your <code>HelloFormStuff</code> Activity has the following
default implementation of the {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
<pre>
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
</pre>
<p>Now select which kind of form widget you'd like to create:</p>
<ul>
<li><a href="#CustomButton">Custom Button</a></li>
<li><a href="#EditText">Edit Text</a></li>
<li><a href="#Checkbox">Checkbox</a></li>
<li><a href="#RadioButtons">Radio Buttons</a></li>
<li><a href="#ToggleButton">Toggle Button</a></li>
<li><a href="#RatingBar">Rating Bar</a></li>
</ul>
<h2 id="CustomButton">Custom Button</h2>
<p>In this section, you will create a button with a custom image instead of text, using the {@link
android.widget.Button} widget and an XML file that defines three different images to use for the
different button states. When the button is pressed, a short message will be displayed.</p>
<img src="images/android_pressed.png" style="float:right;" title="android_pressed.png"/>
<img src="images/android_focused.png" style="float:right;clear:right;" title="android_focused.png"/>
<img src="images/android_normal.png" style="float:right;clear:right;" title="android_normal.png"/>
<ol>
<li>Copy the images on the right into the <code>res/drawable/</code> directory of
your project. These will be used for the different button states.</li>
<li>Create a new file in the <code>res/drawable/</code> directory named
<code>android_button.xml</code>.
Insert the following XML:
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
&lt;item android:drawable="@drawable/android_pressed"
android:state_pressed="true" />
&lt;item android:drawable="@drawable/android_focused"
android:state_focused="true" />
&lt;item android:drawable="@drawable/android_normal" />
&lt;/selector>
</pre>
<p>This defines a single drawable resource, which will change its image based on the current
state of the button. The first <code>&lt;item></code> defines
<code>android_pressed.png</code> as the image when the button is pressed (it's been
activated); the second <code>&lt;item></code> defines <code>android_focused.png</code> as the image
when the button is focused (when the button is highlighted using the trackball or directional
pad); and the third <code>&lt;item></code> defines <code>android_normal.png</code> as the image
for the normal state (when neither pressed nor focused). This XML file now represents a single
drawable resource and when referenced by a {@link android.widget.Button} for its background,
the image displayed will change based on these three states.</p>
<p class="note"><strong>Note:</strong> The order of the <code>&lt;item></code> elements is
important. When this drawable is referenced, the <code>&lt;item></code>s are traversed in-order to
determine which one is appropriate for the current button state. Because the "normal" image is last,
it is only applied when the conditions <code>android:state_pressed</code> and
<code>android:state_focused</code> have both evaluated false.</li>
<li>Open the <code>res/layout/main.xml</code> file and add the {@link
android.widget.Button} element:
<pre>
&lt;Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:background="@drawable/android_button"
android:onClick="onButtonClicked"/>
</pre>
<p>The <code>android:background</code> attribute specifies the drawable resource to use for the
button background (which, when saved at <code>res/drawable/android.xml</code>, is
referenced as <code>@drawable/android</code>). This replaces the normal background image
applied by the system with the drawable created above, which changes its image based on
the button state.</p>
<p>The attribute <code>android:onClick</code> specifies the name of a method in your activity
that the system should call when the user clicks the button. You'll create that method next.</p>
</li>
<li>To make the button do something when pressed, add the following
method inside your {@link android.app.Activity} class:
<pre>
public void onButtonClicked(View v) {
// Do something when the button is clicked
Toast.makeText(HelloFormStuff.this, "Button clicked", Toast.LENGTH_SHORT).show();
}
</pre>
<p>When you specify this kind of method, which is used in your layout file with the {@code
android:onClick} attribute, the method must be <code>public</code>, have a <code>void</code> return
value, and accept a single {@code android.view.View} parameter. When the system calls this method,
it passes the {@code android.view.View} that was clicked.</p>
</li>
<li>Now run the application.</li>
</ol>
<h2 id="EditText">Edit Text</h2>
<p>In this section, you will create a text field for user input, using the {@link
android.widget.EditText} widget. Once text has been entered into the field, the "Enter" key will
display the text in a toast message.</p>
<ol>
<li>Open the <code>res/layout/main.xml</code> file and add the {@link android.widget.EditText}
element (inside the {@link android.widget.LinearLayout}):
<pre>
&lt;EditText
android:id="@+id/edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</pre>
</li>
<li>To do something with the text that the user types, add the following code
to the end of the {@link android.app.Activity#onCreate(Bundle) onCreate()} method:
<pre>
final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &amp;&amp;
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
</pre>
<p>This captures the {@link android.widget.EditText} element from the layout and adds an {@link
android.view.View.OnKeyListener}. The {@link android.view.View.OnKeyListener} must implement the
{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent)} method, which
defines the action to be made when a key is pressed while the widget has focus. In this case, the
method is defined to listen for the Enter key (when pressed down), then pop up a {@link
android.widget.Toast} message with the text that has been entered. The {@link
android.view.View.OnKeyListener#onKey(View,int,KeyEvent)} method should always return
<code>true</code> if the event has been handled, so that the event doesn't bubble-up (which would
result in a carriage return in the text field).</p>
</li>
<li>Run the application.</li>
</ol>
<h2 id="Checkbox">Checkbox</h2>
<p>In this section, you will create a checkbox for selecting items, using the {@link
android.widget.CheckBox} widget. When the checkbox is pressed, a toast message will
indicate the current state of the checkbox.</p>
<ol>
<li>Open the <code>res/layout/main.xml</code> file and add the {@link android.widget.CheckBox}
element (inside the {@link android.widget.LinearLayout}):
<pre>
&lt;CheckBox android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="check it out"
android:onClick="onCheckboxClicked"/>
</pre>
<p>The attribute <code>android:onClick</code> specifies the name of a method in your activity
that the system should call when the user clicks the check box. You'll create that method next.</p>
</li>
<li>To do something when the state is changed, add the following method inside your {@link
android.app.Activity} class:</p>
<pre>
public void onCheckboxClicked(View v) {
// Perform action on clicks, depending on whether it's now checked
if (((CheckBox) v).isChecked()) {
Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show();
}
}
</pre>
<p>When you specify this kind of method, which is used in your layout file with the {@code
android:onClick}
attribute, the method must be <code>public</code>, have a <code>void</code> return value, and
accept a single {@code android.view.View} parameter. When the system calls this method, it
passes the {@code android.view.View} that was clicked. In this example, the {@code
android.view.View} is cast to a {@link android.widget.CheckBox} to determine whether the widget
has been checked or unchecked. The {@link android.widget.CheckBox} widget
handles its own state changes, so you only need to query the current state.</p>
</li>
<li>Run it.</li>
</ol>
<p class="note"><strong>Tip:</strong> If you need to change the state
yourself (such as when loading a saved {@link android.preference.CheckBoxPreference}),
use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
android.widget.CompoundButton#toggle()} method.</p>
<h2 id="RadioButtons">Radio Buttons</h2>
<p>In this section, you will create two mutually-exclusive radio buttons (enabling one disables
the other), using the {@link android.widget.RadioGroup} and {@link android.widget.RadioButton}
widgets. When either radio button is pressed, a toast message will be displayed.</p>
<ol>
<li>Open the <code>res/layout/main.xml</code> file and add two {@link
android.widget.RadioButton}s, nested in a {@link android.widget.RadioGroup} (inside the {@link
android.widget.LinearLayout}):
<pre>
&lt;RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
&lt;RadioButton android:id="@+id/radio_red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red"
android:onClick="onRadioButtonClicked"/>
&lt;RadioButton android:id="@+id/radio_blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Blue"
android:onClick="onRadioButtonClicked"/>
&lt;/RadioGroup>
</pre>
<p>It's important that the {@link android.widget.RadioButton}s are grouped together by the {@link
android.widget.RadioGroup} element so that no more than one can be selected at a time. This logic
is automatically handled by the Android system. When one {@link android.widget.RadioButton} within
a group is selected, all others are automatically deselected.</p>
<p>The attribute <code>android:onClick</code> specifies the name of a method in your activity
that the system should call when the user clicks the radio button. You'll create that method
next.</p>
</li>
<li>To do something when each {@link android.widget.RadioButton} is selected, add the following
method inside your {@link android.app.Activity} class:</p>
<pre>
public void onRadioButtonClicked(View v) {
// Perform action on clicks
RadioButton rb = (RadioButton) v;
Toast.makeText(HelloFormStuff.this, rb.getText(), Toast.LENGTH_SHORT).show();
}
</pre>
<p>When you specify this kind of method, which is used in your layout file with the {@code
android:onClick}
attribute, the method must be <code>public</code>, have a <code>void</code> return value, and
accept a single {@code android.view.View} parameter. When the system calls this method, it
passes the {@code android.view.View} that was clicked.</p>
<p>Because each {@link android.widget.RadioButton} widget is grouped into a {@link
android.widget.RadioGroup}, each widget handles its own state changes when a new button is
selected.</p>
</li>
<li>Run the application.</li>
</ol>
<p class="note"><strong>Tip:</strong> If you need to change the state
yourself (such as when loading a saved {@link android.preference.CheckBoxPreference}),
use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
android.widget.CompoundButton#toggle()} method.</p>
<h2 id="ToggleButton">Toggle Button</h2>
<p>In this section, you'll create a button used specifically for toggling between two
states, using the {@link android.widget.ToggleButton} widget. This widget is an excellent
alternative to radio buttons if you have two simple states that are mutually exclusive ("on" and
"off", for example).</p>
<ol>
<li>Open the <code>res/layout/main.xml</code> file and add the {@link android.widget.ToggleButton}
element (inside the {@link android.widget.LinearLayout}):
<pre>
&lt;ToggleButton android:id="@+id/togglebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOn="Vibrate on"
android:textOff="Vibrate off"
android:onClick="onToggleClicked"/>
</pre>
<p>The attributes <code>android:textOn</code> and <code>android:textOff</code> specify the text
for the button when the button has been toggled on or off. The default values are "ON" and
"OFF".</p>
<p>The attribute <code>android:onClick</code> specifies the name of a method in your activity
that the system should call when the user clicks the button. You'll create that method next.</p>
</li>
<li>To do something when the user clicks the button, add the following
method inside your {@link android.app.Activity} class:</p>
<pre>
public void onToggleClicked(View v) {
// Perform action on clicks
if (((ToggleButton) v).isChecked()) {
Toast.makeText(HelloFormStuff.this, "Toggle on", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HelloFormStuff.this, "Toggle off", Toast.LENGTH_SHORT).show();
}
}
</pre>
<p>When you specify this kind of method, which is used in your layout file with the {@code
android:onClick}
attribute, the method must be <code>public</code>, have a <code>void</code> return value, and
accept a single {@code android.view.View} parameter. When the system calls this method, it
passes the {@code android.view.View} that was clicked.</p>
<p>In this example, the callback
method checks the new state of the button, then shows a {@link android.widget.Toast} message that
indicates the current state.</p>
<p>Notice that the {@link android.widget.ToggleButton} handles its own state change between checked
and unchecked, so you just ask which it is.</p>
<li>Run the application.</li>
</ol>
<p class="note"><strong>Tip:</strong> If you need to change the state
yourself (such as when loading a saved {@link android.preference.CheckBoxPreference}),
use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
android.widget.CompoundButton#toggle()} method.</p>
<h2 id="RatingBar">Rating Bar</h2>
<p>In this section, you'll create a widget that allows the user to provide a rating,
with the {@link android.widget.RatingBar} widget.</p>
<ol>
<li>Open the <code>res/layout/main.xml</code> file and add the {@link android.widget.RatingBar}
element (inside the {@link android.widget.LinearLayout}):
<pre>
&lt;RatingBar android:id="@+id/ratingbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1.0"/>
</pre>
<p>The <code>android:numStars</code> attribute defines how many stars to display for the rating
bar. The <code>android:stepSize</code> attribute defines the granularity for each
star (for example, a value of <code>0.5</code> would allow half-star ratings). </p>
</li>
<li>To do something when a new rating has been set, add the following code
to the end of the {@link android.app.Activity#onCreate(Bundle) onCreate()} method:
<pre>
final RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar);
ratingbar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
Toast.makeText(HelloFormStuff.this, "New Rating: " + rating, Toast.LENGTH_SHORT).show();
}
});
</pre>
<p>This captures the {@link android.widget.RatingBar} widget from the layout with {@link
android.app.Activity#findViewById(int)} and then sets an {@link
android.widget.RatingBar.OnRatingBarChangeListener}. The {@link
android.widget.RatingBar.OnRatingBarChangeListener#onRatingChanged(RatingBar,float,boolean)
onRatingChanged()} callback method then defines the action to perform when the user sets a rating.
In this case, a simple {@link android.widget.Toast} message displays the new rating.</p>
<li>Run the application.</li>
</ol>
<p>If you've added all the form widgets above, your application should look like this:</p>
<img src="images/hello-formstuff.png" width="150px" />
<h3>References</h3>
<ul>
<li>{@link android.widget.ImageButton}</li>
<li>{@link android.widget.EditText}</li>
<li>{@link android.widget.CheckBox}</li>
<li>{@link android.widget.RadioButton}</li>
<li>{@link android.widget.ToggleButton}</li>
<li>{@link android.widget.RatingBar}</li>
</ul>