Android Logo MathCS.org - Android

Simple Widgets and Layout

java -> android -> simple interaction ...

We created our first application as a static application that would run without any user interaction. It did play music and detect our location, which is pretty sophisticated, but without user interaction it was pretty lame. In this segment we will create a still simple app but show the rudiments of creating a user interface that allows for interaction with a user.

First, create a new project in Eclipse:

As before, a new project with the source code, manifest, resources, and other files is created for us and we can open FirstInteract.java for editing.

Widgets

To interact with the user your application needs to display buttons, menus, text boxes, lists, etc. and react to the user interacting with these elements. Adding such an element usually involves three steps:

  1. Decide which element is most appropriate and create an instance of it, either locally or globally as a field.
  2. Specify the layout of your new element in relation to all other visible elements.
  3. Intercept events that your element produces as a result of the user interacting with it, and execute the appropriate code at the appropriate time.

Many of the most commonly used user interface elements are collectively known as "widgets" and can be found in the android.widget package. Technically widgets are View objects, but it is easier to collectively refer to them as widgets, or common and simple user interface objects. They include, for example:

Layouts

Android supports a number of layouts, which can be nested and combined with each other. Layouts are direct subclasses of ViewGroup i.e. they are used to organize a group of View items (or widgets). The more commonly used layouts are:

There is also an AbsoluteLayout, but that one is not useful because it does not work well across different devices, resolutions, and orientations. There are many parameters that specify details of how these layouts work but they are best defined via XML data files. We'll move to design with XML soon, but for now we'll define our layout programmatically (with Java code) for simplicity, which is, actually, not the recommended method.

A Sample App with UI Elements

We'll start with the basic source code created by our new project wizard in FirstInteract.java

public class FirstInteract extends Activity 
{
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

It should compile without problems but nothing will happen so no need to run it (yet). Create a new layout and change the content view to use that layout:

    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);

        setContentView(layout);
    }

This would arrange all items horizontally, but since there are no items (yet) no need to run it. Create a button, a label, and an analog clock and add them to the layout in order:

    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);

        Button button = new Button(this);
        button.setText("Click Me");
        
        TextView label = new TextView(this);
        label.setText("This is a label");
  
        AnalogClock clock = new AnalogClock(this);
        
        layout.addView(button);
        layout.addView(label);
        layout.addView(clock);
        
        setContentView(layout);
    }

Now we have something to show for our effort. Run this program in the emulator and you should see the three widgets like this:

FirstInteract

Of course clicking on the button will not have any effect. We need to "activate" the button before it can cause any noticeable action, which requires three steps:

  1. define a listener, i.e. a class that can react to events generated by the button (caused by a user clicking it)
  2. register the listener class with our button so it can intercept the events generated by the button (and caused by a user)
  3. provide handles (variables pointing) to widgets that the listener needs to access

Say, for example, we want to be able to click on the button to change the text of the label. We need to

  1. create the listener class by creating an inner class (a class within a class) that implements the OnClickListener interface of a View as a field (sometimes this is done as an anonymous class but I don't like it because it makes your code harder to manage)
  2.  register the listener with our button by calling the setOnClickListener method of the button, using a new instance of our listener as input
  3. define some of our widgets - namely the one containing the label - as fields instead of local variables

Here is a complete listing of our program (the analog clock is purely for show and is not really having anything to do):

public class FirstInteract2 extends Activity 
{
	// defining the relevant UI elements as fields
	private TextView label = null;
	private Button button = null;
	
	// defining handler classes as a private inner class
	private class ButtonListener implements View.OnClickListener
	{
		public void onClick(View v)
		{
			label.setText("Stop, it tickles ...");
		}		
	}
	
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        // initializing the UI elements defined as fields
        button = new Button(this);
        button.setText("Click Me");
        
        label = new TextView(this);
        label.setText("This is a label");
  
        AnalogClock clock = new AnalogClock(this);

        // defining the layout and adding the UI widgets
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.addView(button);
        layout.addView(label);
        layout.addView(clock);
        
        // registering listeners to widgets
        button.setOnClickListener(new ButtonListener());
        setContentView(layout);
    }
}

When you run this app, it will look as before but the button is now "activated": when you click on it, the text of our label will change. It will change every time you click the button, but you will of course only notice it the first time when the initial text is different.

Exercise: As an exercise, modify the program to alternate between two different texts, i.e. when you click the button the first time it changes to "It tickles", when you click again the text changes to "No, please stop", when you click again it goes back to "It tickles", and so on.

You don't need any new widgets but you could add a boolean field to store which of the two texts you are displaying. Then you can check in the listener method which text is shown already and change to the other text (as well as switch the state of the boolean variable). I leave the details to you.

FirstInteractExercise: Add the following widget to your program to see how they look:

a CheckBox, a DatePicker, a DigitalClock, an EditText field, a RadioButton, a TimePicker, and ToggleButton
Do they scroll if they no longer fit the screen of your device? If you run the program on a real device, what happens if the display switches from  portrait mode to landscape mode?

To the left are some of these widgets, make sure to identify them. Also be sure to run the program on a real device, not only on the emulator, to see how each element reacts to touch and switching orientation.

If you like to experiment, try to nest linear layouts inside other linear layouts to create complex and appealing arrangements of widgets, or play with the other layouts. If you rather see a worked-out example, check the next section.