Android, A Complete Course,
From Basics to Enterprise Edition
Android, A
Complete Course, From Basics to Enterprise Edition
Composants graphiques élémentaires Android.
1.1 Utilisation des layouts XML
1.5 Les conteneurs et widgets évolués
Cet article est extraie du livre
« Android, A Complete Course », disponible sur Android2ee.com.
Les
exemples ou les programmes présents dans cet ouvrage sont fournis pour
illustrer les descriptions théoriques. Ce code est libre de toute
utilisation mais n'est pas distribuable.
La
distribution du code est reservée au site :
La
propriété intellectuelle du code appartient à :
L’utilisation
de ces codes est sous votre unique responsabilité et personne d’autre que vous
ne pourra être tenu responsable des préjudices ou dommages de quelques natures
que ce soit pouvant résulter de son utilisation.
Tous
les noms de produits ou marques cités dans cet ouvrage sont des marques déposés
par leurs propriétaires respectifs.
Publié
par http://android2ee.com
Titre Original : Android, A Complete Course, From Basics to Enterprise Edition.
Édition Française.
ISBN : 979-10-90388-00-0
Copyright © 2011 by Mathias Séguy
Aucune
représentation ou reproduction, même partielle, autre que celles prévues à
l’article L. 122-5 2° et 3° a) du code de la propriété intellectuelle ne peut
être faite sans l’autorisation expresse de Mathias Seguy ou, le cas échéant,
sans le respect des modalités prévues à l’article L. 122-10 dudit code
L’utilisation de fichiers XML pour le positionnement des éléments graphiques d’une application Android est préconisée.
Ex :
Le fichier res\layout\main.xml
<?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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/button"
android:text=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
Et on l’utilise dans le code Java qui correspond juste à une application de type Activités:
public
class MainActivity extends
Activity implements View.OnClickListener {
/**
* A button */
private
Button btn;
/**
* A dummy counter */
private
int count;
/** Called when the activity
is first created. */
@Override
public
void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
//Récupère
le fichier main.xml pour construire l’IHM
setContentView(R.layout.main);
//Instancie
le bouton en récupérant son Id,
//on
peut ensuite utiliser le bouton normalement.
btn=(Button)findViewById(R.id.button);
btn.setOnClickListener(this);
btn.setText("Hello");
}
public
void onClick(View view)
{
count++;
btn.setText("Hello
"+count);
}
}
Il y a 4 types principaux de Layout :
· LinearLayout, c’est l’alignement linéaire qui s’appuie sur des boîtes qui sont alignées en colonnes ou en lignes.
· RelativeLayout, c’est un placement relatif des composants les uns par rapport aux autres.
· TableLayout, c’est un placement dans une table.
· ScrollView et HorizontalScrollView, c’est un placement utilisant le scroll pour gérer les débordements.
Chacun à ses spécificités et permet d’effectuer les IHMs. À choisir selon ses gouts.
Les widgets élémentaires sont TextField (les labels), Bouton, Image, Check Box, EditText et RadioBoutton.
Leur hiérarchie est la suivante (elles héritent donc les unes des autres de leurs propriétés, de leurs méthodes).
v TextView
Ø Bouton
Ø EditText
Ø CompoundButton
§ CheckBox
§ RadioButton
· ImageView
Ø ImageButton
Une TextView est un composant permettant d’afficher un texte statique, souvent appelé label.
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Un champ
texte"
/>
Un bouton est un composant cliquable affichant un texte.
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/button"
android:text=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:onClick=”uneMethode” />
Ces composants servent à afficher des images. L’ImageButton permet d’écouter facilement les clics effectués sur le composant.
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/icon"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:src="@drawable/molecule"
/>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/icon"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
android:src="@drawable/molecule"
/>
Ce composant permet d’afficher un texte qui soit éditable.
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/field"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:singleLine="false"
/>
Ce composant permet d’afficher un booléen avec lequel l’utilisateur peut interagir.
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cette case est : decochee" />
Ces composants sont des cases à cocher regroupées au sein d’un groupe (le GroupButton) en choix exclusif.
<RadioGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RadioButton android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Caillou" />
<RadioButton android:id="@+id/radio2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ciseaux" />
<RadioButton android:id="@+id/radio3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Papier" />
</RadioGroup>
Tous les composants qui héritent de TextView possèdent un large ensemble de méthodes permettant leur manipulation en Java. Ces méthodes sont pour la plupart usuelles pour les développeurs ayant un peu d’expérience en IHM. Citons simplement les plus utiles.
Les méthodes les plus utiles pour savoir dans quel état est le composant.
textView.hasFocus();
textView.isPressed();
textView.isSelected();
textView.isShown();
Les méthodes pour gérer le texte
affiché.
//
text management
textView.setText("the
text of the text view");
//
or append text
int
start = 0, end
= 3;
textView.append("the
text to add", start, end);
//
retrieve text
String
displayedText = (String) textView.getText();
//
get text lengh in characters' number
textView.length();
Les méthodes graphiques permettant de gérer l’affichage de ce texte :
int
color = 11254;
//
setting background color
textView.setBackgroundColor(color);
// Sets
the horizontal alignment of the text and the vertical gravity that will be used
when
//
there is extra space in the TextView beyond what is required for the text
itself.
//
Should be used in the layout.xml : android:gravity
textView.setGravity(Gravity.CENTER_HORIZONTAL
| Gravity.CENTER_VERTICAL);
//
Sets the color used to display the selection highlight.
textView.setHighlightColor(color);
//
managing the lines
//
set one line with the horizontal scroll or not
textView.setHorizontallyScrolling(true);
//
Define the one line attribute. The XML attribute to use is android:singleLine
textView.setSingleLine(true);
//
Set the text font size (in pixel)
textView.setTextSize(16);
//
to set multilines: The XML attribute to use is android:lines
textView.setLines(3);
//
or to set a range of multi lines: The XML attribute to use are
android:minLines,
//
android:maxLines
textView.setMinLines(1);
textView.setMaxLines(3);
Voici le code pour ajouter :
· un listener qui écoute les changements associés au texte affiché
· un listener qui écoute les clics effectués sur le composant
· un listener qui écoute quand le composant gagne ou perd le focus
// A
text changed listener
textView.addTextChangedListener(new
TextWatcher() {
@Override
public
void onTextChanged(CharSequence s,
int start,
int before,
int count)
{
}
@Override
public
void beforeTextChanged(CharSequence s,
int start,
int count,
int after)
{
}
@Override
public
void afterTextChanged(Editable s)
{
}
});
// A
click listener
textView.setOnClickListener(new
OnClickListener() {
@Override
public
void onClick(View v)
{
}
});
// A
focus changed listener
textView.setOnFocusChangeListener(new
OnFocusChangeListener() {
@Override
public
void onFocusChange(View v,
boolean hasFocus)
{
}
});
Ajouter une description de votre composant :
//
Sets the View description. It briefly describes the view and is primarily used
for
//
accessibility support. Set this property to enable better accessibility support
for your
//
application. This is especially true for views that do not have textual
representation
//
(For example, ImageButton).
textView.setContentDescription("a
short description for accessibility");
Changer votre composant en un composant qui est de type erreur :
//
to set that Text View an Error Text view with an error icon and a popup that
display the
//
message in parameter
textView.setError("my
error message to be displayed in the popup");
La méthode qui définit le placement de la scroll bar :
//
you can set a specific scrollBar's style can be:
//
SCROLLBARS_INSIDE_OVERLAY
//
SCROLLBARS_INSIDE_INSET
//
SCROLLBARS_OUTSIDE_OVERLAY
//
SCROLLBARS_OUTSIDE_INSET
textView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
Enfin, la méthode qui permet de mettre en place une ombre sous le texte du composant :
//
or define the shadow to draw for the text:
//
The XML Attributes to use are: android:shadowColor, android:shadowDx,
android:shadowDy,
//
android:shadowRadius
int
radius=1,dx=2,dy=2;
textView.setShadowLayer(radius, dx, dy, color);
Ces widgets servent d’aide à la rédaction ou à la sélection d’éléments.
Ces widgets s’appuient sur des adaptateurs qui offrent une interface commune aux modèles de données sous-jacents d’un widget de sélection de données. Ils fournissent la liste des données et les convertissent en différentes vues spécifiques qui sont utilisées par le widget de sélection pour l’affichage.
Il y a 6 types de listes de sélections :
· La liste de base : ListView
· La combo box : Spinner
· Le GridView qui affiche les choix dans une grille
· L’AutoCompleteTextView qui affiche un sous-ensemble de données en utilisant l’entrée utilisateur comme filtre sur ces données. Les données sont affichées comme avec le Spinner.
· Les Galleries qui affichent les données sous forme d’une liste horizontale sont souvent utilisées pour la sélection d’images.
Cet exemple montre une liste et un champ texte. Quand on clique sur un item de la liste, le champ texte récupère la valeur de l’item sélectionné.
Trois choses sont importantes dans ce premier exemple :
· L’utilisation de android.R.layout.simple_list_item_1 dans la définition de l’ArrayAdapter qui définit comment seront présentés les items au sein de la liste.
· L’utilisation du tag @android :id/list comme identifiant de la ListView qui sera automatiquement interprété par l’ActivityList comme étant la liste principale.
· Mon activité étend ListActivity.
/**
* @author
mathias seguy
* @goals
This class aims to show a simple List Activity
*/
public
class ListViewTuto extends
ListActivity {
/***
A text view */
TextView textView;
/***
The dummy data list */
String[] items
= {"item1","item2","item3","item4","item5","item6"
};
/**
*The arrayAdapter that manage the data displayed */
ArrayAdapter<String> arrayAdapter;
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
//
Define the Adapter (Context, ListView Ressource, The items to display)
arrayAdapter=new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
items);
//or
using string values stored in the resources:
String[] itemsFromRes=getResources().getStringArray(R.array.itemsList);
arrayAdapter=new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
itemsFromRes);
//Set
the ArrayAdapter to the ListActivity
setListAdapter(arrayAdapter);
//The
text view that displays the current selected item
textView
= (TextView) findViewById(R.id.text);
}
/*
(non-Javadoc)@see android.app.ListActivity#onListItemClick(android.widget.ListView,
android.view.View, int, long)
*/
public
void onListItemClick(ListView parent,
View v, int position,
long id)
{
textView.setText(items[position]);
}
}
Où le fichier xml de déclaration des éléments graphiques est :
<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/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
/>
</LinearLayout>
Dans votre fichier strings.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, ListViewTuto!</string>
<string name="app_name">ListViewTuto2</string>
<string-array>
<item>items1</item>
<item>items2</item>
<item>items3</item>
<item>items4</item>
<item>items5</item>
<item>items6</item>
</string-array>
</resources>
Cet exemple montre un champ texte d’édition, un bouton et une liste. Il permet d’ajouter des items à la liste en remplissant le champ texte puis en appuyant sur le bouton.
Ici, seul le R.android.layout.simple_list_item_1 est le paramètre à bien positionner.
Dans votre code Java :
public
class ListViewTuto extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Building mainLayout
setContentView(R.layout.main);
// Retrieve the ListView,
EditText and Button
ListView
listView = (ListView)
findViewById(R.id.myListView);
final EditText editText = (EditText)
findViewById(R.id.editTask);
Button
button = (Button) findViewById(R.id.addButton);
// Création de la liste des
to do items
final ArrayList<String> items = new ArrayList<String>();
items.add("items1");
// Création de l'array
adapter pour lier l'array à la listview
final ArrayAdapter<String> arrayAdapter;
arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
// Liaison de l'array
adapter à la listview.
listView.setAdapter(arrayAdapter);
// Add the button listener
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Add the value of the
EditText in the list
arrayAdapter.add(editText.getText().toString());
// Delete the content of the
Edit text
editText.setText("");
}
});
}
}
Dans votre layout :
<?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"
>
<EditText
android:id="@+id/editTask"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/addButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/btnAdd"
/>
<ListView
android:id="@+id/myListView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Dans votre fichier values/strings.xml :
<?xml version="1.0"
encoding="utf-8"?>
<resources>
<string name="hello">Hello World,
ListViewTuto!</string>
<string name="app_name">ListViewTuto</string>
<string name="btnAdd">Add</string>
</resources>
public
class AutoCompleteTuto extends
Activity implements TextWatcher {
/**
* A textView */
TextView textView;
/**
* An AutoComplete TextView */
AutoCompleteTextView autoCompleteTextView;
/**
* The dummy data */
String[] items
= { "A_item1", "B_item2",
"C_item3", "D_item4",
"E_item5", "F_item6"
};
/**
*The arrayAdapter that manage the data displayed */
ArrayAdapter<String> arrayAdapter;
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
//
create the TextView
textView
= (TextView) findViewById(R.id.textView);
//
create the AutoCompleteTextView
autoCompleteTextView
= (AutoCompleteTextView) findViewById(
R.id. autoCompleteTextView);
//
Add the this.TextWatcher as listener
autoCompleteTextView.addTextChangedListener(this);
//
Define the Adapter (Context, ListView Ressource, The items to display)
arrayAdapter
= new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items);
autoCompleteTextView.setAdapter(arrayAdapter);
}
/**************************************************************************/
/**
TextWatcher override methods **********************************************/
/**************************************************************************/
/**
(non-Javadoc) *
*
@see android.text.TextWatcher#onTextChanged(java.lang.CharSequence, int, int,
int)
*/
public
void onTextChanged(CharSequence s,
int start,
int before,
int count)
{
autoCompleteTextView.setText(textView.getText());
}
/* *
(non-Javadoc) *
* @see
android.text.TextWatcher#beforeTextChanged(java.lang.CharSequence, int, int,
int)
*/
public
void beforeTextChanged(CharSequence s,
int start,
int count,
int after)
{
//
needed for interface, but not used
}
/* *
(non-Javadoc) *
* @see
android.text.TextWatcher#afterTextChanged(android.text.Editable)
*/
public
void afterTextChanged(Editable s)
{
//
needed for interface, but not used
}
}
Et l’on trouve dans le fichier de description des IHM :
<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/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<AutoCompleteTextView android:id="@+id/autoCompleteTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:completionThreshold="3"/>
</LinearLayout>
Les listes sont personnalisables, on peut les enrichir (ajouter des icones,…) pour afficher les données à sélectionner.
Le DatePicker et le TimePicker servent à choisir la date et l’heure.
Le code Java:
/**
* @author
mathias1
* @goals
This class aims to display a date Picker and a time picker and retrieve their
value
*/
public
class DateAndTimePickerTuto extends
Activity {
/**
* The formatter used */
DateFormat fmtDateAndTime
= DateFormat.getDateTimeInstance();
/**
* A label to display new date and time to the user */
TextView calendarTextView;
/**
* The time object representation used by the class */
Calendar calendar=
Calendar.getInstance();
/**
* The datePicker object */
DatePickerDialog datePickerDialog;
/**
* The listener for date changed */
DatePickerDialog.OnDateSetListener
dateSetListener = new
DatePickerDialog.OnDateSetListener() {
public
void onDateSet(DatePicker view,
int year,
int monthOfYear,
int dayOfMonth)
{
//
When a date is selected update the calendar object
calendar.set(Calendar.YEAR,
year);
calendar.set(Calendar.MONTH,
monthOfYear);
calendar.set(Calendar.DAY_OF_MONTH,
dayOfMonth);
//
and the associated textView
updateLabel();
}
};
/** * The timepicker object */
TimePickerDialog timePickerDialog;
/**
* The listener for time changed */
TimePickerDialog.OnTimeSetListener
timeSetListener = new
TimePickerDialog.OnTimeSetListener() {
public
void onTimeSet(TimePicker view,
int hourOfDay,
int minute)
{
//
When a date is selected update the calendar object
calendar.set(Calendar.HOUR_OF_DAY,
hourOfDay);
calendar.set(Calendar.MINUTE,
minute);
//
And the associated textView
updateLabel();
}
};
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
//instanciate the
date picker
datePickerDialog=new
DatePickerDialog(this, dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
//Define
the button that show the date Picker
Button btn
= (Button) findViewById(R.id.btnDate);
btn.setOnClickListener(new
View.OnClickListener() {
public
void onClick(View v)
{
//
Instanciate the DatePicker using this as context, the dateListener
defined above and the
current time
new
DatePickerDialog(getApplicationContext(),
dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)).show();
}
});
//instanciate the
timepicker
timePickerDialog=new
TimePickerDialog(this, timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
true);
//Define
the button that show the time Picker
btn
= (Button) findViewById(R.id.btnTime);
btn.setOnClickListener(new
View.OnClickListener() {
public
void onClick(View v)
{
//
Instanciate the TimePicker using this as context, the timeListener defined
above and the current time
new
TimePickerDialog(getApplicationContext(),
timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
true).show();
}
});
//Define
the text view that displays the selected time
calendarTextView
= (TextView) findViewById(R.id.calendarTextView);
updateLabel();
}
/**
* Calls by the Time and Date SetListeners */
private
void updateLabel() {
calendarTextView.setText(fmtDateAndTime.format(calendar.getTime()));
}
}
La déclaration graphique:
<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/calendarTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button android:id="@+id/btnDate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Choisir une
date"
/>
<Button android:id="@+id/btnTime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Choisir une
heure"
/>
</LinearLayout>
Il suffit de les déclarer dans votre fichier de ressources des éléments graphiques :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<AnalogClock android:id="@+id/analog"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
/>
<DigitalClock android:id="@+id/digital"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/analog"
/>
</RelativeLayout>
Ils seront alors automatiquement détectés et vous pourrez les utiliser dans votre classe java en y faisant référence R.id.analog.
Ces deux widgets sont une barre de progression, mais là où la première est une sortie (on affiche une progression), la seconde est une entrée (on choisit une valeur au sein d’un intervalle).
Pour la ProgressBar les méthodes les plus utiles sont :
· setMin, setMax (une ProgressBar utilise des entiers),
· setProgress pour fixer le positionnement du curseur ou incrementProgressBy pour la faire avancer avec une valeur prédéterminée,
· setInderterminate (pour la barre infinie).
Pour la SeekBar on utilise le setOnSeekBarChangeListener pour écouter les changements de position du curseur. Il possède une valeur entre 0 et 100.