Benutzerschnittstellen

Einleitung

Benutzerschnittstellen bestehen in Android aus sogenannten Views und Gruppierungen von Views. Dazu werden die Klassen android.view.View und android.view.ViewGroup bereit gestellt. Durch Ableitung von diesen Klassen werden konkrete Elemente der Benutzerschnittstelle erzeugt. Dazu gehören unter anderem die Klassen Button , CheckBox , LinearLayout , TabWidget und viele weitere. Views bilden eine Hierarchie. Das heißt, jedes Elemente kann optional Kindelemente besitzen.

Android bietet die Möglichkeit, Benutzerschnittstellen statisch oder programmatisch zu erzeugen. Statisch bedeutet, dass mittels XML-Dateien die Schnittstelle beschrieben wird. Damit können viele Einsatzgebiete bereits abgedeckt werden. Es kann aber auch nötig sein, eine Benutzerschnittstelle erst an Hand bestimmter Eingabedaten zur Laufzeit zu generieren. Dies kann getan werden, indem konkreter Java-Code zur Instanziierung der GUI-Elemente programmiert wird. Es ist aber auch möglich, XML-basierte Views zur Laufzeit programmatisch zu verändern.

In diesem Tutorial wird eine einfache grafische Benutzeroberfläche erstellt. Diese wird im Kern aus XML-basierten Elementen bestehen. Durch ein Menu und Ereignisse wird zwischen verschiedenen Ansichten, Activities genannt, gewechselt. Auch die programmatische Erstellung einiger Teile wird vorgestellt.

Layouts

Layouts beschreiben die Anordnung von Elementen der Benutzeroberfläche. Dies geschieht vorrangig durch XML-Beschreibungen. Diese können per Hand oder durch einen grafischen Editor, welcher durch die Android Development Tools bereitgestellt wird, erzeugt werden. Am häufigsten wird das LinearLayout verwendet. Dieses ordnet seine Kindelemente nacheinander entweder horizontal oder vertikal an.

Nach der Erstellung eines neuen Projekts wird die Datei main.xml aus dem Ordner res/layout geöffnet. Es öffnet sich der grafische GUI Editor. Mittels Drag 'n' Drop fügen wir der GUI nun ein Texview und einen Button hinzu:

UI mit Text und Button

Mit einem Rechtsklick auf ein Element kann mit dem Menupunkt Edit ID die ID des Elementes geändert werden:

Änderung von ID's

Ereignisse

Beispielhaft für die Arbeit mit Ereignissen verwenden wir Button-Clicks. Um auf ein Ereignis zu reagieren, benötigen wir einen Listener. Um diesen zu erstellen, gibt es zwei Möglichkeiten. Die erste besteht darin, in der Methode onCreate() der Activity eine Referenz auf den Button zu erhalten und diesem mit der Methode setOnClickListener() einen Listener zuzuweisen. Die zweite Möglichkeit ist die Zuweisung über den grafischen Editor. Um beide Möglichkeiten zu zeigen, wird der Benutzeroberfläche zuerst ein zweiter Button hinzugefügt. Die ID's der Buttons werden auf "button1" und "button2" geändert. Der erste Button soll programmatisch einen Listener zugeordnet bekommen. Beim zweiten Button wird dies per Editor erledigt. In beiden Fällen soll sich der Text in dem Textview-Objekt ändern.

Das Layout sollte im XML-Code etwa wie folgt aussehen:

<?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:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button2" />

</LinearLayout>

Programmatische Zuweisung eines Listeners

Um einen Listener programmatisch zuzuweisen, muss die Methode onCreate() angepasst werden. Zuerst wird eine Referenz auf den ersten Button benötigt. Dazu nutzt man die Methode findViewById . Anschließend kann der Listener erzeugt werden, ähnlich wie in Swing-Applikationen. Innerhalb des Listeners werden wir wie im Tutorial über Activities eine Nachricht ausgeben. Der Quelltext der Activity sieht anschließend wie folgt aus:

package de.hszg.mobileapps.ui;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class UITestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button button1 = (Button) findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener() {
			
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "Button 1 wurde gedrückt", 
                    Toast.LENGTH_LONG).show();
            }
        });
    }
}

Listener per Editor setzen

Um per Editor einen Listener zu setzen, klickt man rechts auf den Button (Button 2) und wählt die Eigenschaft "OnClick" aus, wie in der folgenden Abbildung ersichtlich:

Listener per Editor setzen

Im sich öffnenden Fenster gibt man den Namen der aufzurufenden Methode an, zum Beispiel onButtonClicked . Dieser Name wird nun automatisch in die XML-Datei eingetragen:

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="onButtonClicked"
    android:text="@string/button2" />

Startet man die App nun und klickt auf den zweiten Button, so erhält man eine Fehlermeldung, da die angegebene Methode ja noch nicht angelegt wurde. In der Activity wird nun eine Methode mit Namen onButtonClicked angelegt. Diese erwartet als Parameter ein Objekt vom Typ View :

public void onButtonClicked(View v) {
    Toast.makeText(getApplicationContext(), "Button 2 wurde gedrückt", Toast.LENGTH_LONG).show();
}

Beide Varianten, um Ereignisse mit Listenern zu verbinden werden in der Praxis eingesetzt. Welche von beiden sollte man nun wählen? Wann immer möglich, ist die zweite Variante zu bevorzugen, da der Java-Code besser lesbar bleibt. Die programmatische Variante wird normalerweise nur gewählt, wenn auch die entsprechenden Elemente der Benutzeroberfläche programmatisch erzeugt wurden, und somit das Setzen des Listeners per Editor nicht möglicht ist.

Menus

Im Folgenden wird ein einfaches Menu erstellt, mit dem von der Haupt-Activity zu einer anderen Activity gewechselt werden kann. Dazu erstellt man im Ordner res einen Unterordner menu. Mittels Rechtsklick auf den neu erstellten Ordner fügt man nun eine neue Android XML Datei mit dem Typ "Menu" hinzu:

Neue Android XML Datei

Menu

Im Editor wird nun ein neues Menu-Item hinzugefügt und ein Titel angegeben. Damit das Menu angezeigt wird, muss die Methode onCreateOptionsMenu() implementiert werden:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);

    return true;
}

Die Aktionen, welche bei Auswahl eines Menuelementes geschehen sollen, werden in einer weiteren Methode implementiert. Diese nennt sich onOptionsItemSelected(). Als Parameter erhält man das ausgewählt Menu-Item. Mit einer switch-Anweisung kann nun das die auszuführende Aktion bestimmt werden. Im konkreten Fall soll eine neue Activity gestartet werden. Wir verwenden die eine bereits existierende Activity:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.item1:
    	Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivity(intent);
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}