Chapitre 2.2: Composants graphiques complexes sous Android

Image non disponible

Android2ee


La Formation et l'Expertise Android à votre service


CommeAirFrance, Orange,Capgemini, Atos WorldLine et bien d'autres.
Vous aussi,
Bénéficiez des meilleures formations Android du moment


Cet article est extrait 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 réservée au site :

http://android2ee.com.

La propriété intellectuelle du code appartient à :

Mathias Séguy.

ISBN : 979-10-90388-00-0

Copyright © 2011 by Mathias Séguy






Android2EE est référencé en tant qu'organisme de formation, vous pouvez faire prendre en charge tout ou partie du montant de cette formation par votre OPCA. Les formations Android d'Android2EE sont éligibles au titre duDIF et CIF.

Commentez

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Les IHMs des Activités - éléments complexes

 

I-A. Les onglets

 

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, icônes 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:

 
Sélectionnez
<?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.

 
Sélectionnez
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 :

 
Sélectionnez
<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 :

 
Sélectionnez
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);
    }

}

I-A-1. Une autre activité dans un onglet

 

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.

I-B. Les vues basculantes : ViewFlipper

 

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 par les TabWidget).

I-B-1. Vue basculante statique

 

L'objet principal est ViewFlipper, qui se décrit dans le layout.xml, et sa méthode showNext.

 
Sélectionnez
<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é :

 
Sélectionnez
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();
            }
        });
    }
}

I-B-2. Vue basculante dynamique

 

Exemple d'ajout de vues à la volée :

Le descripteur d'IHM ne décrit pas le contenu du ViewFlipper :

 
Sélectionnez
<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:

 
Sélectionnez
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:

 
Sélectionnez
<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:

 
Sélectionnez
<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>

I-C. Les tiroirs : SlidingDrawer

 

Les tiroirs sont des widgets qui s'affichent et se cachent au-dessus de la vue courante. Pour cette raison, il ne peut être le fils que des layouts de type RelativeLayout ou FrameLayout.

Un tiroir (SlidingDrawer) est défini 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'emploi de ce widget sont :

  • 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:

 
Sélectionnez
<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 :

 
Sélectionnez
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
        }
    });
}}

II. Méthodes de saisie : clavier physique ou logiciel

 

De manière transparente, Android propose le clavier logiciel (IME Input Method Editor) quand aucun clavier physique n'existe dans la manipulation de champs texte (EditorText). Nous verrons dans ce chapitre comment personnaliser 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 :

  • text
  • textCapCharacters
  • textCapWords
  • textCapSentences
  • textAutoCorrect
  • textAutoComplete
  • textMultiLine
  • textImeMultiLine
  • textNoSuggestions
  • textUri
  • textEmailAddress
  • textEmailSubject
  • textShortMessage
  • textLongMessage
  • textPersonName
  • textPostalAddress
  • textPassword
  • textVisiblePassword
  • textWebEditText
  • textFilter
  • textPhonetic
  • number
  • numberSigned
  • numberDecimal
  • phone
  • datetime
  • date
  • time

Ces inputTypes définissent le clavier qui apparaîtra lorsque l'utilisateur remplira le champ EditText ; ainsi, s'il est d'inputType number, le clavier n'aura que des chiffres…

Exemple :

 
Sélectionnez
<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 de savoir ce 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é :

 
Sélectionnez
<?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 comment 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).

III. Les menus

 

Il y a deux types de menus : les menus contextuels et les menus d'option (menu usuel).

III-A. Menu d'option

 

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 (six icônes maximum 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é:

 
Sélectionnez
@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, il faut utiliser la méthode add de la classe Menu. Cette méthode possède quatre paramètres :

  • Un identifiant de groupe permettant de regrouper un ensemble d'items en choix exclusif (comme ButtonGroup).
  • Un identifiant de choix servant à identifier l'item du menu par un entier. Cet entier est récupéré 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 maîtrisez pas cet attribut).
  • Le texte à afficher par le menu.

Ce qui donne :

 
Sélectionnez
menu.add(Menu.NONE, ITEM1, Menu.NONE, "Item 1");

Les identifiants de choix et de groupes permettent ceci :

  • 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.

III-B. Menu contextuel

 

Le principe est identique au menu d'option. Le menu contextuel apparaît lorsqu'un utilisateur laisse appuyé un élément de la vue.

Les différences entre menu d'option et menu contextuel :

  • Enregistrer les widgets 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 contextuels 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.

III-C. Exemple

 

Descripteur d'IHM:

 
Sélectionnez
<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:

 
Sélectionnez
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);
    }
}

III-D. Utilisation de l'inflation pour les menus (description via fichier XML d'un menu)

 

L'élément racine doit se nommer Menu, ses 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 :

 
Sélectionnez
<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 :

 
Sélectionnez
<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 :

 
Sélectionnez
public class MenuXmlTuto extends Activity {
    /**
     * the Menu of the activity
     */
    private Menu theMenu = null;
    
    // Création de l'activité (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));
    }
}

IV. Polices de caractères

 

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 :

 
Sélectionnez
<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>

Ajouter une police.

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, ne pas trop ajouter de polices sous peine de pénaliser le téléphone en lui volant toute sa mémoire (une police peut aller de 70Ko à plus de 500Ko !!!).

V. Intégrer le navigateur WebKit à une activité : le widget WebView

 

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 :

 
Sélectionnez
<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 :

 
Sélectionnez
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);
    }
}

V-A. Activation JavaScript

 

Par défaut il est désactivé. Pour l'activer :

 
Sélectionnez
//Set JavaScript enable
browser.getSettings().setJavaScriptEnabled(true);
//Javascript can open a new window
browser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

V-B. La méthode LoadData

 

Au lieu de faire charger une URL, il est possible de charger des données HTML qui seront affichées au sein du navigateur.

 
Sélectionnez
//or load data
browser.loadData("<html><body>Bonjour !</body></html>","text/html", "UTF-8");

V-C. Méthodes de navigation

 

Pour des raisons d'ergonomie, WebView ne possède pas de barre de navigation. Mais les méthodes pour naviguer existent (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.

VI. Messages surgissants : Toast et AlertDialog

 

VI-A. Toast

 

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 Length_Long ou Length_Short:

 
Sélectionnez
//Dans le cas  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  l'on se trouve dans une activité, this=getApplicationContext
Toast.makeText(this, "A toast", Toast.LENGTH_SHORT).show();

VI-B. Les AlertDialogs

 

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:

 
Sélectionnez
//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();

VII. Android2EE: La Formation et l'Expertise Android à votre service

Image non disponible

Android2EE


Android2EE espère que cet article vous a été utile et profitable.
En tant qu'experts et formateurs sur le développement Android, nous serions heureux de vous accueillir à nos formations pour pouvoir continuer à vous expliquer l'art du développement Android (nous avons des tonnes de choses à vous raconter). Nous sommes persuadés qu'elles sont excellentes, les stagiaires qui les ont suivies le sont aussi.
Alors si vous souhaitez devenir un excellent développeur Android, il ne vous reste plus que deux choses à faire:

  • nous envoyer un mail à
  • convaincre votre service R.H. de l'importance de cette formation pour vous et pour l'entreprise.



Pour plus de renseignements, n'hésitez pas à cliquer sur les liens ci-dessous.



Comme AirFrance , Orange, Capgemini , Atos WorldLine et bien d'autres.
Vous aussi,
Bénéficiez des meilleures formations Android du moment



Android2EE est référencé en tant qu'organisme de formation, vous pouvez faire prendre en charge tout ou partie du montant de cette formation par votre OPCA. Les formations Android d'Android2EE sont éligibles au titre du DIF et CIF.

VIII. Récupération des tutoriels et lecture des autres chapitres du livre

Vous pouvez lire l'ensemble de l'ouvrage sur Android2EE, à cet adresse Livre en consultation. Les 28 chapitres sont disponibles. Un tutorial sera bientôt disponible sur le site Android2EE.

IX. Articles, conférences et autres tutoriaux made in Android2EE

Vous pouvez trouver d'autres articles sur developpez.com rédigés par Android2EE.

Vous pouvez trouver les projets Android open sources d'Android2EE sur GitHub.

Android2EE sur Github

GDirectionsApiUtils pour vous simplifiez l'utilisation du service REST Google Api Direction (les itinéraires entre deux points).

Le MythicServiceHelper est un projet simplifiant la communication entre les services et les activités. Il est mieux d'utiliser, à l'heure d'aujourd'hui, EventBus ou Otto. Vous pouvez aller le voir quand même par curiosité.

Le Bluetooth avec Android expliqué. Ce projet est un chat bluetooth qui vous montre, par l'exemple, comment mettre en place une communication BlueTooth entre deux appareils Android.

Le projet ForecastYahooRest a pour objectif de vous expliquer comment mettre une architecture saine pour vos projets Android pour effectuer des appels REST. Ce projet est lié à la conférence "An Android Journey" que vous pouvez retrouver sur Android2ee.

Le projet SignInWithGoogleTutorialvous explique comment mettre l'authentification Google au sein de vos applications. Il est lié à la conférence Google Sign In que vous pouvez retrouver sur Android2EE.

Vous pouvez trouver les supports des conférences d'Android2EE sur SlideShared.

Android2EE sur SlideShare

Retrouvez la liste des tutoriaux Android2EE de la formation complète. C'est pas ma meilleure conférence :)

An Android Journey La conférence 2014 d'Android2EE qui vous donne toutes les astuces, les bonnes pratiques et les bons conseils à mettre en place dans vos applications pour en faire des applications exceptionnelles.

ActionBarCompat Cette conférence vous explique comment mettre en place l'ActionBar dans vos applications pour toutes les versions du système en utilisant l'ActionBarCompat.

GoogleSignIn L'authentification Google vous est expliquée dans cette conférence.

Android ProTips Cette conférence a été donnée à la DroidCon Paris 2013 pour vous présenter les meilleurs conseils sur le développement Android donnée aux GoogleIo. Ce sont mes bonnes pratiques favorites.

Architecture Android Une peu d'architecture, ça vous dit? Cette conférence est dédiée à l'architecture, quels sont les problèmes rencontrés et les bonnes pratiques à mettre en place.

Android, un nouveau futur s'ouvre à nous Cette conférence, donnée à Brazzaville, présente les enjeux de la mobilité et en particulier ma vision du futur relative à Android.

Combining the power of Eclipse with Android Cette conférence, donnée à l'EclipseDay 2012, présente comment utiliser la DDMS et chasser les fuites mémoires au sein de vos applications Android.

A Quick OverviewCette conférence, donnée au CocoHeads Toulouse en 2012, est une introduction à la programmation Android.

Android A Quick Course @DevoxxFr Cette présentation est un extraie de la conférence "Android A Quick Course", donnée à DevoxxFrance, pour apprendre le développement Android. Les vidéos (3 heures tout de même sont disponibles sur le site Android2EE ou sur Parleys)

Les vidéos de certaines de ces conférences sont disponibles à l'adresse suivante : Les vidéos


X. Le site Android2ee, une référence pour le développement Android.

Le site Android2EE vous propose des tutoriels, des articles, des vidéos, des conférences, des eBooks en libre consultation pour monter en compétence sur la technologie Android.

Vous trouverez tout cela dans la partie « Open Resources ».

N'hésitez plus visitez-le ! Android2EE

XI. Android2ee vous présente l'Ebook de programmation Android

Le nouveau système d'exploitation de Google pour les téléphones portables et les nouvelles tablettes est là. Sa réputation est solide, il envahit le monde de la téléphonie, il est ouvert et offre des outils de développement Java au monde des programmeurs. Il ouvre les portes du développement mobile à tous les développeurs objets avec un coût minime pour la montée en compétence. Une seule question se pose :

Êtes-vous prêts ?

L'objectif de ces livres est très clair : vous permettre en un temps record d'être autonome en programmation Android. Si vous êtes un programmeur Java (débutant ou confirmé), le but est que vous soyez autonome en moins de dix jours. C'est cet objectif qui est à l'origine de ce livre, permettre aux collaborateurs de mon entreprise de monter en compétence sur cette technologie avec rapidité et efficience. Vous serez alors à même de concevoir une application, de l'implémenter, de la tester, de l'internationaliser et de la livrer à votre client.

Lancez-vous dans la programmation Android et faites-vous plaisir !

Vous serez aussi capable de connaître et comprendre quelles sont les considérations à avoir lorsque l'on a à charge une application Android en tant que professionnel de l'informatique. Quelle est la stratégie de tests à utiliser ? Comment signer son application ? Comment la déployer ? Comment mettre en place la gestion du cycle de vie de l'application ? Comment implémenter l'intégration continue ?

Soyez efficient dans l'encadrement de vos projets Android d'entreprise.


L'achat d'un EBook vous donne accès à l'ensemble des tutoriaux Android2EE, plus de 50 projets Android qui vous apprendrons à mettre en place une notion spécifique (SlidingDrawer, Parsing d'un service REST, Mise en place d'un service, d'un ContentProvider...). Vous pouvez dès maintenant vous lancer dans la programmation Android, n'hésitez pas faîtes vous plaisir, il y a 75% de réduction sur les EBooks en ce moment:

Apprendre la programmation Android avec les EBooks Android2EE

Android, A Complete Course, From Basics To Enterprise Edition (fr).

Android, A Quick Course (fr).

Android, An Entreprise Edition Vision (fr).

Les eBooks sont disponibles en français et en anglais, à votre convenance.


Nota Bene: l'ouvrage "Android, A Complete Course, From Basics To Enterprise Edition" réunit, au sein d'un même document, les livres "Android, A Quick Course" et "Android, An Enterprise Edition Vision" permettant au lecteur d'avoir dans un même document la totalité des préoccupations liées à la mise en place de projets Android, de la montée en compétence en tant que développeur à la gestion du cycle de vie du projet.

XII. Remerciements

Nous remercions ced pour sa relecture orthographique.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (0)

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2014 Mathias Seguy. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.