Android, A Complete Course,
From Basics to Enterprise Edition
Android, A
Complete Course, From Basics to Enterprise Edition
Composants graphiques complexes Android.
Les IHMs des Activités – Elements complexes
1.2 Méthodes de saisie : Clavier physique ou logiciel
1.5 Intégrer le navigateur WebKit à une activité : le
widget WebView
1.6 Messages surgissants : Toast et AlertDialog
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
Les IHMs des Activités – Elements complexes
Pour la mise en place d’onglets, il faut s’appuyer sur les widgets suivants :
· TabHost est le conteneur général,
· TabWidget implémente la ligne des boutons d’onglets (qui contiennent labels, icones ou une vue),
· FrameLayout est le conteneur des contenus des onglets : chaque onglet est un fils de FrameLayout.
Il existe un TabActivity, comme ListActivity, qui encapsule un motif d’interface graphique classique dans une sous-classe d’activité. Ce n’est pas nécessaire, une activité classique peut très bien utiliser également des onglets.
Quelques règles syntaxiques :
· L’identifiant du TabWidget doit être @android :id/tabs,
· Dans le cas d’une TabActivity l’identifiant du TabHost est @android :id/tabhost.
Exemple de la définition statique d’onglets:
<?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">
<TabHost android:id="@+id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="62px">
<DigitalClock android:id="@+id/digital"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
/>
<AnalogClock android:id="@+id/analog"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
/>
</FrameLayout>
</TabHost>
</LinearLayout>
On remarque que TabHost contient deux objets distincts, le TabWidget qui est la ligne des boutons d’onglets et le FrameLayout qui lui contient les onglets. Ainsi, c’est le FrameLayout qui contient les widgets visualisés dans l’onglet.
public
class StaticTabPane extends
Activity {
/** Called when the activity
is first created. */
@Override
public
void onCreate(Bundle savedInstanceState)
{
//
Instanciation of the View
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//
Instanciation of the Tab Host the one that contains the tabPanels
TabHost tabs
= (TabHost) findViewById(R.id.tabhost);
tabs.setup();
//
Instanciation of the first tab component
TabHost.TabSpec spec
= tabs.newTabSpec("digital");
spec.setContent(R.id.digital);
//Definition
of the label to display for the tabPanel
spec.setIndicator("Digital
Clock");
//Adding
the first tabPanel to the TabHost
tabs.addTab(spec);
//Instanciation
of the second tab component
spec
= tabs.newTabSpec("analogic");
spec.setContent(R.id.analog);
//
Definition of the label to display for the tabPanel
spec.setIndicator("Analogic
Clock");
//Adding
the second tabPanel to the TabHost
tabs.addTab(spec);
}
}
Exemple pour la manipulation dynamique de la création d’onglets. Le fichier de déclaration GUI ci-dessus change à peine, l’AnalogClock étant remplacée par un Button :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TabHost android:id="@+id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="62px">
<DigitalClock android:id="@+id/digital"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
/>
<Button android:id="@+id/button"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Bouton
semi-aleatoire"
/>
</FrameLayout>
</TabHost>
</LinearLayout>
Seul le code Java change fortement :
public
class DynamicTabPane extends
Activity {
/**
* The tabHost */
TabHost tabHost;
/** * The On click Listener */
private
OnClickListener ocl = new
View.OnClickListener() {
public
void onClick(View view)
{
addTabSpec();
}
};
/** * The Button that adds a new TabSpec */
private
Button btn;
@Override
public
void onCreate(Bundle icicle)
{
//
Instanciate the activity
super.onCreate(icicle);
setContentView(R.layout.main);
//
Instanciate the TabHost
tabHost
= (TabHost) findViewById(R.id.tabhost);
tabHost.setup();
//
Instanciate the first tabPanel
TabHost.TabSpec tabSpec
= tabHost.newTabSpec("digital");
tabSpec.setContent(R.id.digital);
tabSpec.setIndicator("Clock");
//
Adding the first tabPanel
tabHost.addTab(tabSpec);
//
Instanciate the second tabPanel
tabSpec
= tabHost.newTabSpec("button");
tabSpec.setContent(R.id.button);
tabSpec.setIndicator("Button");
//
Adding the second tabPanel
tabHost.addTab(tabSpec);
//
Adding functionalities to the button: When a clic is done, a new TabPanel is
created
btn
= (Button) findViewById(R.id.button);
if
(btn == null)
{
Toast.makeText(this,
"nullPointeur exception",
Toast.LENGTH_LONG).show();
} else
{
Toast.makeText(this,
"not nullPointeur exception",
Toast.LENGTH_LONG).show();
btn.setOnClickListener(ocl);
}
}
/**
* @param
tabHost
*/
private
void addTabSpec() {
Toast.makeText(this,
"A new tab is created",
Toast.LENGTH_LONG).show();
//
Retrieve the TabSpec of the TabHost and creating a new entry
TabHost.TabSpec spec
= tabHost.newTabSpec("analogic");
//
Creating a new content to the tabPanel using TabContent factory
spec.setContent(new
TabHost.TabContentFactory() {
public
View createTabContent(String tag) {
//
This method has to return a view, the tag is the one define by TabSpec
return
(new AnalogClock(getApplicationContext()));
}
});
//
or using an already defined element:
// spec.setContent(R.id.digital);
//
Define the Tab label
spec.setIndicator("Analogic");
//
Adding the new tabPanel to the TabHost
tabHost.addTab(spec);
}
}
Il est possible d’intégrer une autre activité au sein d’un onglet. Cet exemple est expliqué au chapitre 5.3.5 Cas particulier : La navigation par onglets.
On peut souhaiter pouvoir avoir des onglets sans barre d’onglets, c'est-à-dire, basculer d’une vue à une autre au sein de l’activité.
Cela est possible avec l’objet ViewFlipper qui hérite de FrameLayout. Le basculement entre les vues est alors à mettre en place (contrairement aux onglets où le processus est pris en charge pas les TabWidget).
L’objet principal est ViewFlipper qui se décrit dans le layout.xml et sa méthode showNext.
Le layout :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:id="@+id/flip "
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Flip !"
/>
<ViewFlipper android:id="@+id/flipper"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="first"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="second"
/>
</ViewFlipper>
</LinearLayout>
Et le code associé :
public
class FlipTuto extends
Activity {
/**
*The flipperView View */
ViewFlipper flipperView;
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
//Retrieve
the flipperView
flipperView
= (ViewFlipper) findViewById(R.id.flipper);
//Instanciate
the button
Button btn
= (Button) findViewById(R.id.flip);
//When
the button is click, just flip to the next element
btn.setOnClickListener(new
View.OnClickListener() {
public
void onClick(View view)
{
flipperView.showNext();
}
});
}
}
Exemple d’ajout de vues à la volée :
Le descripteur d’IHM ne décrit pas le contenu du ViewFlipper :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ViewFlipper android:id="@+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</ViewFlipper>
</LinearLayout>
Le code Java:
public
class FlipDynamicTuto extends
Activity {
/***
The dummy data list */
static
String[] items = { "item1",
"item2", "item3",
"item4", "item5",
"item6" };
/**
* The viewFlipper
*/
final
ViewFlipper viewFlipper;
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
//Retrieve
the viewFlipper
viewFlipper
= (ViewFlipper) findViewById(R.id.details);
//
Define animation object for the flip
viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
//Add
view
for
(String item : items)
{
Button btn
= new Button(this);
btn.setText(item);
//When
the button is click, just flip to the next element
btn.setOnClickListener(new
View.OnClickListener() {
public
void onClick(View view)
{
viewFlipper.showNext();
}
});
//Add
a new View to the viewFlipper.
viewFlipper.addView(btn,
new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
}
//Or
make an automatic flipping (in ms)
viewFlipper.setFlipInterval(2000);
//And
launch it
viewFlipper.startFlipping();
}
}
Les descripteurs d’animations :
res\anim\push_left_in.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="300"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="300" />
</set>
res\anim\push_left_out.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="300"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="300" />
</set>
Les tiroirs sont des widgets qui s’affichent et se cachent au-dessus de la vues courante. Pour cette raison, il ne peut être le fils que des layouts de type RelativeLayout ou FrameLayout.
Un tiroir (SlidingDrawer) est définit par une poignée (le plus souvent ImageView) et un contenu qu’il pointe au travers des balises android:handle et android:content. L’ouverture et la fermeture par toucher de la poignée sont automatiquement gérées par la poignée.
Les méthodes utiles à l’utilisation de ce widget :
· open(), close(), toggle() pour ouvrir, fermer et switcher instantanément,
· animateOpen, animateClose, animateToggle pour ouvrir, fermer et switcher en utilisant une animation,
· lock, unlock désactive/active l’écoute des clics utilisateurs,
· Ajouter des écouteurs pour l’ouverture du tiroir, sa fermeture, son mouvement.
Exemple :
Descripteur de ressources GUI:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<SlidingDrawer
android:id="@+id/drawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:handle="@+id/handle"
android:content="@+id/content">
<ImageView
android:id="@id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tray_handle_normal"
/>
<Button
android:id="@id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Button"
/>
</SlidingDrawer>
</FrameLayout>
Code Java :
public class SlidingDrawerTuto extends Activity {
@Override
public
void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
// Retrieve the
SlidingDrawer
final SlidingDrawer slidingDrawer = (SlidingDrawer)
findViewById(R.id.sliding);
// Listen for states changed
slidingDrawer.setOnDrawerOpenListener(new OnDrawerOpenListener(){
@Override
public void onDrawerOpened() {//Do something, for example
change background picture:
slidingDrawer.getHandle().setBackgroundResource(R.drawable.slidingOpen);
}});
slidingDrawer.setOnDrawerScrollListener(new OnDrawerScrollListener() {
@Override
public void onScrollStarted() {//Do something
}
@Override
public void onScrollEnded() {//Do something
}
});
slidingDrawer.setOnDrawerCloseListener(new OnDrawerCloseListener() {
@Override
public void onDrawerClosed() {//Do something
}
});
}}
De manière transparente, Android propose le clavier logiciel (IME Input Method Editor) quand aucun clavier physique n’existe dans la manipulation de champ texte (EditorText). Nous verrons dans ce chapitre comment customiser ce comportement par défaut.
Depuis Android 1.5 un seul attribut sert à définir le style des champs EditText, android:inputType. Ces styles peuvent être séparés par un | de manière à se cumuler. La liste des inputTypes possibles est :
Ces inputTypes définissent le clavier qui apparaitra lorsque l’utilisateur remplira le champ EditText ; ainsi il est d’inputType number, le clavier n’aura que des chiffres…
Exemple :
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1"
>
<TableRow>
<TextView
android:text="Aucune regle speciale : "
/>
<EditText />
</TableRow>
<TableRow>
<TextView
android:text="Adresse email : "
/>
<EditText
android:inputType="text|textEmailAddress"
/>
</TableRow>
<TableRow>
<TextView
android:text="Nombre decimal signe : "
/>
<EditText
android:inputType="number|numberSigned|numberDecimal"
/>
</TableRow>
<TableRow>
<TextView
android:text="Date :"
/>
<EditText
android:inputType="date"
/>
</TableRow>
<TableRow>
<TextView
android:text="Texte multi-lignes : "
/>
<EditText
android:inputType="text|textMultiLine|textAutoCorrect"
android:minLines="3" android:gravity="top"
/>
</TableRow>
</TableLayout>
La seconde préoccupation associée à ce clavier logiciel est que devient l’activité lorsque le clavier apparaît :
· Il peut pousser l’activité vers le haut quand il apparaît (mode adjustPan)
· Il peut modifier la taille de l’activité pour pouvoir se mettre à ses côtés sans rien changer d’autre (mode adjustResize).
· En mode paysage, il peut masquer l’activité et prendre tout l’écran pour améliorer la saisie.
Ce mode est choisi par Android (en fonction de votre layout), pour le modifier il faut le définir au niveau de l’activité, ce qui s’effectue dans le manifeste de cette activité :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.commonsware.android.imf.two"
android:versionCode="1"
android:versionName="1.0">
<application android:label="@string/app_name"
android:icon="@drawable/icon">
<activity android:name=".keyboardTuto"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>
</manifest>
Les modes disponibles sont :
· StateUnspecified (le système choisit l’état le plus approprié)
· stateUnchanged (le système laisse l’état du clavier en l’état quand l’activité passe au premier plan)
· stateHidden (le système cache le clavier quand l’activité passe au premier plan)
· stateAlwaysHidden (le système cache le clavier quoi qu’il arrive)
· stateVisible (le système affiche le clavier quand l’activité passe au premier plan)
· stateAlwaysVisible (le système affiche le clavier quoi qu’il arrive)
· adjustUnspecified (le système choisit comme le clavier s’insère dans votre activité)
· adjustResize (le système change la taille des composants de l’activité pour afficher le clavier)
· adjustPan (le système pousse votre activité pour afficher le clavier)
Ces modes sont cumulables les uns avec les autres avec l’opérateur « | » (ex : adjustResize|visible).
Il ya deux types de menus : les menus contextuels et les menus d’option (menu usuel).
Il se déclenche en appuyant sur un bouton de menu et a deux états : icône ou étendu. Il s’ouvre en mode icône (6 icones max avec le dernier qui vaut « + » pour afficher le reste du menu en mode étendu).
Deux façons d’implémenter un menu sont possibles, soit en java soit en xml.
La création s’effectue en surchargeant la méthode OnCreateOptionsMenu de l’activité:
@Override
public
boolean onCreateOptionsMenu(Menu
menu) {
populateMenu(menu);
return(super.onCreateOptionsMenu(menu));
}
L’objet menu est accessible directement dans les méthodes surchargées associées aux menus de l’activité.
Pour ajouter des choix et des sous-menus, la méthode add de la classe Menu est à utiliser. Cette méthode possède 4 paramètres :
· Un identifiant de groupe permettant de regrouper un ensemble d’item en choix exclusif (comme ButtonGroup)
· Un identifiant de choix servant à identifier l’item du menu par un entier. Cet entier est récupérer par la méthode onOptionsItemSelected
· Un identifiant d’ordre indiquant un emplacement du choix dans le menu lorsque ce dernier contient des options ajoutées par Android (utiliser Menu.NONE tant que vous ne maitriser pas cet attribut).
· Le texte à afficher par le menu
Ce qui donne :
menu.add(Menu.NONE, ITEM1, Menu.NONE, "Item 1");
Les identifiants de choix et de groupes permettent :
· MenuItem.setCheckable avec un identifiant de choix ajoute une case à cocher à côté du titre de l’item.
· Menu.SetGroupCheckable est identique à GroupButton pour les RadioButtons.
Le principe est identique au menu d’option. Le menu contextuel apparaît lorsqu’un utilisateur laisse appuyer un élément de la vue.
Les différences entre menu d’option et menu contextuel:
· Enregistrer les widget qui porteront le menu contextuel en appelant la méthode registerForContextMenu et en passant le widget (une View).
· Implémenter la méthode OnContextMenu qui reçoit l’objet View en paramètre (ce qui permet d’implémenter plusieurs menus en fonction de cet objet). Cette méthode est appelée à chaque fois que le menu est affiché (contrairement au menu d’options).
Enfin la méthode OnContextItemSelected est partagée par tous les menus contextuel et ne reçoit qu’un MenuItem, il faut donc que les identifiants des items soient tous distincts pour tous les menus contextuels. De plus, getMenuInfo renvoie l’objet ContextMenu.ContextMenuInfo reçu par la méthode onCreateContextMenu.
Descripteur d’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"
android:text="Texte multi-lignes : "/>
<EditText
android:id="@+id/editText"
android:inputType="text|textMultiLine|textAutoCorrect"
android:minLines="3" android:gravity="top"
/>
</LinearLayout>
Code Java:
public
class MenuTuto extends
Activity {
/***
A text view */
TextView textView;
/**
* an Edit Text */
EditText editText;
//Items
Identifier used by the option menu
final
private int
ITEM_ID1 = Menu.FIRST
+ 100001;
final
private int
ITEM_ID2 = Menu.FIRST
+ 100002;
final
private int
ITEM_ID3 = Menu.FIRST
+ 100003;
final
private int
ITEM_ID4 = Menu.FIRST
+ 100004;
//Item
used by the Context Menu
final
private int
ITEM_ID5 = Menu.FIRST
+ 100005;
final
private int
ITEM_ID6 = Menu.FIRST
+ 100006;
final
private int
ITEM_ID7 = Menu.FIRST
+ 100007;
final
private int
ITEM_ID8 = Menu.FIRST
+ 100008;
@Override
public
void onCreate(Bundle icicle)
{
//GUI
instanciation
super.onCreate(icicle);
setContentView(R.layout.main);
//
Graphic elements creation
textView
= (TextView) findViewById(R.id.textView);
editText
=(EditText) findViewById(R.id.editText);
//
Adding the contextual menu on the Widget EditText
registerForContextMenu(editText);
}
/******************************************************************************/
/**
Context Menu ****************************************************************/
/******************************************************************************/
//Create
a context Menu
@Override
public
void onCreateContextMenu(ContextMenu menu,
View v, ContextMenu.ContextMenuInfo menuInfo)
{
populateContextMenu(menu);
}
//Link
the context menu's items selection action with the applyMenuChoice method
@Override
public
boolean onContextItemSelected(MenuItem
item) {
return
(applyMenuChoice(item) || super.onContextItemSelected(item));
}
//
Fill the menu
private
void populateContextMenu(Menu menu)
{
menu.add(Menu.NONE,
ITEM_ID5, Menu.NONE,
getString(R.string.item5));
menu.add(Menu.NONE,
ITEM_ID6, Menu.NONE,
getString(R.string.item6));
menu.add(Menu.NONE,
ITEM_ID7, Menu.NONE,
getString(R.string.item7));
menu.add(Menu.NONE,
ITEM_ID8, Menu.NONE,
getString(R.string.item8));
}
/***********************************************************************/
/**
Option Menu Methods**************************************************/
/***********************************************************************/
//Create
an option Menu
@Override
public
boolean onCreateOptionsMenu(Menu
menu) {
populateOptionMenu(menu);
return
(super.onCreateOptionsMenu(menu));
}
//Link
the option menu's items selection action with the applyMenuChoice method
@Override
public
boolean onOptionsItemSelected(MenuItem
item) {
return
(applyMenuChoice(item) || super.onOptionsItemSelected(item));
}
//
Fill the menu
private
void populateOptionMenu(Menu menu)
{
menu.add(Menu.NONE,
ITEM_ID1, Menu.NONE,
getString(R.string.item1));
menu.add(Menu.NONE,
ITEM_ID2, Menu.NONE,
getString(R.string.item2));
menu.add(Menu.NONE,
ITEM_ID3, Menu.NONE,
getString(R.string.item3));
menu.add(Menu.NONE,
ITEM_ID4, Menu.NONE,
getString(R.string.item4));
}
/**********************************************************************/
/**
Option and Context Menu shared Methods*********************************/
/**********************************************************************/
//Associated
action method when a selction occurs in a menu
private
boolean applyMenuChoice(MenuItem
item) {
//Use
the Item identifier to know the selected one
switch
(item.getItemId()) {
case
ITEM_ID1:
case
ITEM_ID2:
case
ITEM_ID3:
case
ITEM_ID4:
textView.setText("The
item selected from the option Menu is: "+item.getTitle());
break;
case
ITEM_ID5:
case
ITEM_ID6:
case
ITEM_ID7:
case
ITEM_ID8:
editText.append("\r\nThe
item selected from the context Menu is: "+item.getTitle());
break;
}
return
(false);
}
}
L’élément racine doit se nommer Menu, ces fils sont de type « item » ou « group ». Les sous menus sont déclarés comme étant des menus contenus par un item. Tous les items ont un identifiant permettant de les manipuler dans le code Java.
Exemple, le fichier res\menu\sample :
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/item2"
android:orderInCategory="2"
android:title="item2_no_icon" />
<item android:id="@+id/item3"
android:title="Item3_icon"
android:orderInCategory="3"
android:icon="@drawable/icon" />
<item android:id="@+id/item4"
android:orderInCategory="4"
android:enabled="false"
android:title="item4_disable" />
<group android:id="@+id/itemGroup1"
android:menuCategory="secondary"
android:visible="false">
<item android:id="@+id/itemGroup1_item1"
android:orderInCategory="0"
android:title="item 1.1" />
<item android:id="@+id/itemGroup1_item2"
android:orderInCategory="1"
android:title="item1.2" />
</group>
<item android:id="@+id/submenu1"
android:orderInCategory="3"
android:title="submenu">
<menu>
<item android:id="@+id/submenu_item1"
android:title="Item_s1_shown"
android:visible="true"
android:alphabeticShortcut="s" />
<item android:id="@+id/submenu_item2"
android:title="Item_s2_hidden"
android:visible="false"
android:alphabeticShortcut="h" />
</menu>
</item>
</menu>
L’ordre du choix des menus est celui de leur déclaration au sein de ce fichier. Les tags disponibles pour les menus sont :
· Titre (label de l’item)
· Icône (icône de l’item)
· Ordre (pour spécifier un ordre autre que celui de la déclaration des items)
· Activation (android:enable) se manipule en java avec setEnable (pour un item) ou setGroupEnable (pour un groupe)
· Visibilité (android:visible) se manipule en java avec setVisible.
· Les raccourcis (android:alphabeticsShortCut ou android:numericalShortCut)
Le descripteur d’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:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Menu Avaialable"/>
</LinearLayout>
Et le code java :
public
class MenuXmlTuto extends
Activity {
/**
* the Menu of the activity
*/
private
Menu theMenu = null;
//
Création de l’activitée (qui n’est qu’un TextView ; un label quoi)
@Override
public
void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
//
Création du menu d’options associé au fichier xml res\menu\sample
@Override
public
boolean onCreateOptionsMenu(Menu
menu) {
//
instanciation du menu via le fichier XML
new
MenuInflater(getApplication()).inflate(R.menu.sample, menu);
//
the menu et menu sont le même objet
theMenu
= menu;
//
Création du menu comme avant
return
(super.onCreateOptionsMenu(menu));
}
//
Instanciation de l’action associée à la sélection d’un item du menu (mets à
jour le TextView
//
avec le message associé à l’item)
@Override
public
boolean onOptionsItemSelected(MenuItem
item) {
//Do
something:
//for
exemple:
if(item.getItemId()==R.id.submenu_item1){
//show/hide
the hidden item
theMenu.setGroupVisible(R.id.itemGroup1,
!theMenu.findItem(R.id.itemGroup1).isVisible());
//show
hide an item
theMenu.findItem(R.id.item4).setVisible(true);
}else
if(item.getItemId()==R.id.item3){
//Enable/disable
an item
theMenu.findItem(R.id.item4).setEnabled(true);
//enable/disable
a group
theMenu.setGroupEnabled(R.id.itemGroup1,
false);
}
return
(super.onOptionsItemSelected(item));
}
}
Trois polices logiques sont disponibles « sans », « mono » et « sheriff ».
Pour cela dans un TextView (tous les widgets héritent de TextView !!), il faut utiliser l’attribut @android:typeface.
Exemple :
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:id="@+id/sans"
android:text="Hello sans"
android:typeface="sans"
android:textSize="20sp"
/>
</TableRow>
<TableRow>
<TextView
android:id="@+id/serif"
android:text="Hello serif"
android:typeface="serif"
android:textSize="20sp"
/>
</TableRow>
<TableRow>
<TextView
android:id="@+id/monospace"
android:text="Hello monospace"
android:typeface="monospace"
android:textSize="20sp"
/>
</TableRow>
</TableLayout>
Il suffit de créer un répertoire assets/polices dans ressources et de copier les polices de caractères au format TTF (True Type).
Puis en java, affecter cette police aux widgets :
TextView
tv=(TextView)findViewById(R.id.custom);
Typeface
face=Typeface.createFromAsset(getAssets(),"fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
Attention: Les polices pèsent, n’ajouter pas trop de polices sous peine de pénaliser le téléphone en lui volant toute sa mémoire (1 police peut aller de 70Ko à plus de 500Ko !!!).
Ce navigateur possède son propre package (android.webkit). Pour les opérations simples, WebKit est comme un autre widget Android. On l’affiche, on lui passe l’url qu’il doit afficher et il l’affiche :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView android:id="@+id/webkit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Et le code java :
public
class WebKitTutoSimple extends
Activity {
WebView browser;
@Override
public
void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
browser
= (WebView) findViewById(R.id.webkit);
//load
an URL
browser.loadUrl("http://stinfoservices.net/");
//Set
javascript enable
browser.getSettings().setJavaScriptEnabled(true);
//Javascript
can open a new window
browser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
}
Par défaut il est désactivé, pour l’activer :
//Set
JavaScript enable
browser.getSettings().setJavaScriptEnabled(true);
//Javascript
can open a new window
browser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
Au lieu de faire charger une URL, il est possible de charger des données HTML qui seront affichées au sein du navigateur.
//or
load data
browser.loadData("<html><body>Bonjour
!</body></html>","text/html", "UTF-8");
Pour des raisons d’ergonomie, WebView ne possède pas de barre de navigation. Mais les méthodes pour naviguer existe (au développeur d’inventer son IHM associée). Ces méthodes sont :
· reload()
· goBack() (pour revenir en arrière) et canGoBack (pour savoir si la page précédente existe)
· goFroward() et canForward (idem mais pour le forward)
· goBackOrForward(int step) avance ou recule du nombre de pas désignés dans l’historique des pages. (-1 => goBack)
· clearCache
· clearHistory
Le toast est un message évanescent qui s’affiche et disparaît de lui-même. Il laisse le focus où il est déjà.
Pour lancer un Toast il suffit de trois paramètres ; activité courante (le contexte), le texte à afficher ainsi que la durée qui vaut Lenght_Long ou Lenght_Short:
//Dans
le cas où l'on doit récupérer le contexte de l'application (en dehors d'une
activité)
Toast.makeText(getApplicationContext(),
"A toast", Toast.LENGTH_LONG).show();
//Dans
le cas où l'on se trouve dans une activité, this=getApplicationContext
Toast.makeText(this, "A toast", Toast.LENGTH_SHORT).show();
Pour créer une AlertDialog il faut utiliser le builder et chaîner les appels (car les méthodes de builder renvoient builder, pas bête) ou définir les attributs de la fenêtre proprement sur l’objet builder:
//Define
the AlertDialog (android.app.AlertDialog.Builder;)
Builder
alertDialog=new
AlertDialog.Builder(this);
//set
its title
alertDialog.setTitle("The
Alert Dialog Title");
//set
its message
alertDialog.setMessage("The
message to display");
//Define
its neutral button (its label and the associated action)
alertDialog.setNeutralButton("My
neutral Button",
new
DialogInterface.OnClickListener() {
public
void onClick(DialogInterface dlg,
int sumthin)
{
//Do
something.
//if
nothing done, the window will just close
}
});
//Define
its positive button (its label and the associated action)
alertDialog.setPositiveButton(R.string.positiveButton,
new DialogInterface.OnClickListener() {
public
void onClick(DialogInterface dlg,
int sumthin)
{
//Do
something.
//if
nothing done, the window will just close
}
});
//Define
its negative button (its label and the associated action)
alertDialog.setNegativeButton("No", new
DialogInterface.OnClickListener() {
public
void onClick(DialogInterface dlg,
int sumthin)
{
//Do
something.
//if
nothing done, the window will just close
}
});
//show
the alert
alertDialog.show();