oct
13
2010

[Tutoriel Android] Partie 11 – Les TabHost

Les TabHost

Vous avez sûrement dû rencontrer des applications qui avaient une interface sous forme d’onglets. Vous vous demandez peut-être comment fait t’on pour faire ceci sur Android et je l’avoue ce n’est pas facile.

Voici un exemple concret de l’utilisation des onglets sous Android, cela permet d’agencer l’interface facilement si l’utilisateur a besoin d’accéder à des données rapidement.

Notre petit système d’exploitation nous permet de réaliser ceci grâce a un type d’activité bien spéciale : les TabActivity ; vous allez me dire c’est évident, mais le rappeler ne fait de mal à personne.

Il faut savoir qu’une application utilisant des TabHost utilise plusieurs activités, où chaque onglet est une activité différente ou la même mais avec un contenu différent.

En gros, on remarque que l’activité principale héberge un tabhost qui lui-même hébergera une ou plusieurs autres activités, il faut bien mettre cette notion dans la tête.

Création d’un TabHost

Commençons par créer un nouveau projet et changeons l’héritage de notre activité principale en TabActivity.

public class MonActivite extends TabActivity

Puis, nous allons nous tourner vers notre fichier main.xml qui sera là pour definer le layout de l’application :

<?xml version="1.0" encoding="utf-8"?>

<TabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">

<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">

</FrameLayout>

</LinearLayout>

</TabHost>

On voit bien que notre élément de base est le TabHost qui a pour id « @android :id/tabhost », c’est très important sinon la TabActivity ne pourra pas s’y retrouver. Ensuite, un LinearLayout basic, puis un TabWidget qui contient l’id « android :id/tabs », tout aussi important et pour terminer un FrameLayout avec pour id « android :id/tabcontent ». C’est une base obligatoire pour faire fonctionner correctement notre application, oubliez un morceau et vous aurez une jolie erreur.

Nous allons rajouter une activité à notre projet que l’on nommera ActiviteTab. Elle sera utilisée pour afficher les informations dans les onglets, mais vous pouvez très bien utiliser plusieurs activités (une pour chaque onglet).

Puis, nous allons créer un nouveau Layout pour cette activité, je le nommerais tab.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:id="@+id/monTextView"
android:text="Coucou"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal"/>

</LinearLayout>

Voici un layout simple avec uniquement un TextView centré dans la vue.

Nous allons modifier notre activité en conséquence, celle-ci recevra aussi un Intent de l’application principale avec la chaîne de caractères à afficher dans notre Activite.

public class ActiviteTab extends TabActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.tab);

// On récupère notre intent et la valeur nommée valeur
String valeur = getIntent().getStringExtra("valeur");

// On affiche cette chaîne dans le textview
TextView textView = (TextView) findViewById(R.id.monTextView);

textView.setText(valeur);

}

}

Retournons désormais sur notre activité principale qui sera au cœur de notre application.

Nous allons commencer par déclarer un TabHost et un TabSpec, le TabHost servira de lien entre l’IHM et notre code. De plus, il sera le conteneur des différents onglets, quand au TabSpec il sera là pour spécifier les informations de l’onglet (l’activité vers laquelle il pointe, se nom et son image).

private TabHost tabHost;

private TabSpec tabSpec;

Déclarons maintenant notre Intent qui sera utilisé pour lancer les activités enfants :

Intent intent = new Intent(this, ActiviteTab.class);

Ensuite, nous récupèrons le tabhost

tabHost = getTabHost();

Voilà nous avons créé une bonne partie de notre application, la suite nous permettra d’ajouter un onglet à notre TabHost.

Création des onglets

Voyons comment rajouter des onglets à notre TabHost facilement.

Tout d’abord, votre TabHost dispose d’une méthode newTabSpec qui permet de définir un nouvel onglet. Il prend en paramètre un tag, ce tag doit être unique et sous forme d’une chaîne de caractères.

Nous allons aussi rajouter un indicateur à cet onglet, nous pouvons lui définir un titre et une image, l’image n’étant pas obligatoire.

Et pour finir, lui définir l’intent qu’il va exécuter lors de la création de l’onglet.

tabSpec = tabHost.newTabSpec("un").setIndicator("Un", getResources().getDrawable(R.drawable.icon)).setContent(intent);

Puis, il faut ajouter l’onglet à notre tabHost comme ceci :

tabHost.addTab(tabSpec);

Voilà rien de bien compliqué, nous savons ajouter un onglet au TabHost et lui définir une activité.

Je vous mets le code complet de notre activité :

private TabHost tabHost;
private TabSpec tabSpec;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Intent intent = new Intent(this, ActiviteTab.class);

tabHost = getTabHost();

intent.putExtra("valeur", "Coucou tout le monde");

tabSpec = tabHost.newTabSpec("un").setIndicator("Un",
getResources().getDrawable(R.drawable.icon)).setContent(intent);
tabHost.addTab(tabSpec);

intent.putExtra("valeur", "Hello world !");

tabSpec = tabHost.newTabSpec("deux").setIndicator("Deux").setContent(intent);
tabHost.addTab(tabSpec);

}

J’ai ajouté un autre onglet pour bien montrer ce qui se passe.

Permissions

Il ne faut surtout pas oublier de déclarer l’activité dans l’AndroidManifest, sinon nous aurons un jolie FC.

<activity android:name=".ActiviteTab"></activity>

De plus, nous allons definer un thème à notre activité principale pour que l’on n’affiche pas la barre de titre de notre application.

<activity android:name=".MonActivite"

android:label="@string/app_name"

android:theme="@android:style/Theme.NoTitleBar">

@android:style/Theme.NoTitleBar est un thème par défaut contenu dans Android.

Conclusion

Vous devez normalement obtenir ce résultat :

Les TabHost ne sont pas insurmontables, elles ont juste une façon de fonctionner un petit peu spéciale.
J’espère que ce tutoriel vous aura plus et que vous ferez de jolies applications ! (Y’a intérêt) :whistle:

Sources de la formation

  • http://SiteWeb Cédric

    Bonjour, ton tuto est très bien expliqué.

    J’ai remarqué sous eclipse qui donne habituellement un aperçue du main.xml affichait seulement deux ligne :

    Error during post inflation process:
    The FrameLayout for the TabHost has no content. Rendering failed.

    Est-ce important ? serait tu d’ou ça peux venir ? C’est assez gênant pour visualiser..

    (J’utilise la version 2.1,
    Merci :)

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Ne t’en fais pas c’est tout a fait normal le plugin adt ne sais pas afficher le composant tabhost dans eclipse. Peut etre dans une prochaine version, mais il est vrai que cela est embêtant quand on désire visualiser les informations avant de compiler et publier. Bonne soiree et merci encore ;)

  • http://www.widoox.fr adrien

    Hello,

    Juste pour signaler une petite erreur dans le tuto.
    Il faut l’extends en TabActivity et non en Activity sinon cela ne fonctionne pas et on se tape un bon FC :)

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Effectivement, mais on peut aussi utiliser une activity, en modifiant certaines propriétés.

    Coquille corrigée :)

  • http://www.widoox.fr adrien

    ok je savais pas pour la modification des propriétés, tu peux en dires un peu plus ?

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    J’ai pas d’exemples concrets sous la main, mais tu peux utiliser un tabhost dans une activity, pour cela il faut regarder la documentation d’android, mais le mieux si tu n’as qu’une tabhost dans l’activity c’est d’utiliser une tabactivity c’est relativement plus rapide.

  • http://SiteWeb sajid

    Bonjour, vraiment merci pour ton tuto
    c’est très claire et ça m’as beaucoup aidé sur tout que je faisais beaucoup de recherche pour trouver un tuto simple concernant les TabHost
    bonne continuation :wink:

  • http://SiteWeb bab

    Bonjour, votre technique ne semble marcher qu’avec 2 tab au maxim…
    En effet, même en reprennant votre projet exclipse, toutes les tab créé (a partir de la 2eme) vont prendre le contenu du dernier putExtra .

  • http://SiteWeb Jax

    Merci très bon tuto, continu comme ça :wink:

  • http://SiteWeb Sliven

    Bonjour,

    Super tuto, très simple, mais je comfirme le point soulevé par bab :

    Si l’on ajoute un troisième onglet de la même manière que les précédents, le deuxième onglet prend la valeur du troisième.

    Donc cela ne marche que avec 2 onglet :(

    Si quelqu’un a une solution à ce problème cela m’arrangerai ^^

    PS : c’est dans le cadre d’un projet a rendre ….. ce soir XD

  • http://www.agilicio.com Thomas

    Bonjour à tous,

    Pour ma part je peut dépasser les 2 onglets sans problème sans rien faire de spéciale.

    Par contre, comment faire pour avoir des onglets arrondi comme sur les captures d’écrans, les miens sont carrés?

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Par défaut elles sont rondes, mais tu dois être sur android 2.3 non ? dans ce cas elles sont par défaut carré

  • http://SiteWeb Elion

    liens du tuto en version PDF mort !

  • http://jenaipas.... DzUnited

    Salut, merci bcp pour ce tuto, très sympa et très facile….je voulais par contre savoir si on pouvait garder l’onglet, et afficher dans celui-ci une arborescence avec par exemple une listeView qui menera vers des element. Donc en gros, si dans ton onglet un on a une liste et quand on clique sur un element on reste dans le meme onglet, en lancant une activité decrivant l élément choisi…je sais pas si tu m as suis…..mais merci de lire deja…..

  • http://SiteWeb Walido

    salut, je voudrais savoir comment intégrer un list adpter dans chaque tab et merci. :blush: :blush:

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Tout comme pour un listadapter normal, il suffit de faire une liste dans chaque activité.

  • http://SiteWeb Melkorus

    Salut,

    Le tuto est clair et bien commenté….

    Je rencontre une difficulté, peut-être que vous avez une solution.

    J’ai une activité (extends TabActivity), le premier onglet appelle une activity (extends Activity) contenant une liste.
    Lors d’un clic sur un item de cette liste, j’appelle une activité (startActivityForResult).
    Je souhaiterai ouvrir cette activite dans le FrameLayout afin de conserver la TabHost.
    Est-ce possible ?

    Merci

  • http://SiteWeb marven

    merci pour le tuto… est ce que je peut savoir comment ajouter un webview au lieu d’un textview ?? !! surtou lors de l’affectation à l’intent :)
    MERCI

  • http://SiteWeb joe

    merci pour le tuto.. mais je rencontre un petit problem;
    je prepare une application pour mon pfe, la main activité extends (tabactivity)
    et je voudrai qu’un des onglets appel une vue contenant une autre activité qui elle aussi extend une tabactivity. lors du lancement de l’application sur le simulateur, sa ne sort aucun problem, quand j’appuis sur l’onglet en question, l’application bloque et quitte.
    voici le code des 2 classe main et actu (la class en question ) et le code des vue xml :

    main.java :

    import android.app.TabActivity;
    import android.content.Intent;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.widget.TabHost;

    public class main extends TabActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Resources res = getResources();
    TabHost tabHost = getTabHost();
    TabHost.TabSpec spec;
    Intent intent;

    intent = new Intent().setClass(this, categorie.class);
    spec = tabHost.newTabSpec(“Categorie”)
    .setIndicator(“”,res.getDrawable(R.drawable.iccat))

    .setContent(intent);
    tabHost.addTab(spec);

    intent = new Intent().setClass(this, actu.class);
    spec = tabHost.newTabSpec(“Les plus vues”)
    .setIndicator(“”,res.getDrawable(R.drawable.icpluvue))
    .setContent(intent);
    tabHost.addTab(spec);
    }
    }
    et le main.xml :

    la class actu :

    import android.app.TabActivity;
    import android.content.Intent;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.widget.TabHost;

    public class actu extends TabActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.actu);

    Resources res = getResources();
    TabHost tabHost = getTabHost();
    TabHost.TabSpec spec;
    Intent intent;

    intent = new Intent().setClass(this, evenement.class);
    spec = tabHost.newTabSpec(“Evenement”)
    .setIndicator(“”,res.getDrawable(R.drawable.icevent))

    .setContent(intent);
    tabHost.addTab(spec);

    intent = new Intent().setClass(this, trucdepro.class);
    spec = tabHost.newTabSpec(“Truc de pro”)
    .setIndicator(“”,res.getDrawable(R.drawable.ictruc))
    .setContent(intent);
    tabHost.addTab(spec);

    tabHost.setCurrentTab(0);

    }
    }

    et actu.xml :

    si quelqu’un a une solution …
    Merci :smile: :smile:

  • http://SiteWeb joe

    c bon , j vien de trouver !!! j’avais oublier de declarer les activités dans le manifest ! :blush:

  • http://SiteWeb Pierre

    Excellent tuto :heart:

  • http://SiteWeb Fred

    Salut, merci vraiment pour ces tutos, j’ai néanmoins une remarque à faire sur celui-ci :
    ActiviteTab ne doit pas dériver de TabActivity si l’on ne met pas de TabHost dans tab.xml. Je me tapais une FC, et maintenant ça marche nikel en remplacant la classe parent par Activity.

    Merci et bonne continuation

    (Ah, et si tu pouvais ne pas passer de ligne entre chaque ligne de code, ce serait nikel pour le copier-coller, mais bon c’est un détail ;-)

  • http://SiteWeb Droide

    Tu peux simplement copier-coller le texte en appuyant sur l’icône View Source à droite lorsque tu es sur le code. une nouvelle fenêtre s’ouvre, et il n’y a pas de numéros de ligne.

  • http://SiteWeb Mathieu

    Salut,

    Vraiment super tes tutoriaux!!!
    Seulement, j’ai un problème quand je souhaite ajouté une ListView dans un TableHost!!!
    J’ai tout essayé et rien n’y fait…
    Si tu pouvais m’éclairer car là je cale :s

    Merci d’avance!
    Mathieu

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier
  • http://SiteWeb Mathieu

    Merci,

    Mais j’étais déjà tombé sur ces liens et ils ne m’avaient pas vraiment aidé :s
    Enfin bon, j’aurais essayé ;)

    Merci encore!!

  • http://SiteWeb Mathieu

    Finalement, j’ai trouvé.
    Merci encore

  • http://SiteWeb biboune

    Bonjour,

    J’ai un souci avec mon émulateur lorsque je crée une activité qui extends TabActivity :
    Unable to open stack trace file ‘data/anr/traces.txt’ : Permission denied…
    Alors que je peux créer des activité qui extends Activity et là aucune erreur…
    Si tu pouvais m’éclairer ce serait cool ;)

    Merci .

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Essaye de regarder le tracelog complet dans le DDMS (zone en rouge)

    Ca va surement te dire le pourquoi et comment le régler :)

  • http://SiteWeb biboune

    Oui j’ai regardé, mais ca me met plein de uncaught exceptions et l’erreur que je t’ai montré :s
    Ca fait deux jours que je suis dessus et je commence à déprimer…

  • http://SiteWeb biboune

    Désolé de déranger encore une fois, mais j’ai trouvé mon problème :
    quand je met dans mon androidManifest ca plante et je ne comprend pas pourquoi…

    Helop please =)

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Envoi moi ton code par mail, j’y regarderais.

    Cdt.

  • http://SiteWeb biboune

    C’est bon, il me semble que j’ai trouvé l’erreur qui viendrait de mon émulateur, alors je suis en train de le réinstaller voir si ca vient vraiment de là…
    Encore merci…

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    De rien, (j’ai absolument rien fait)

  • bibman

    bonjour excellent tuto ca m’a beaucoup aider :)
    mais j’ai une petite question !
    moi je crée plusieurs onglet (nombre variable en fonction d’une requette sur une BDD)
    et pour chaque onglet j’envoie une variable String via l’intent comme tu fait pour changer le text !
    le problème que je rencontre c’est que le premier onglet recoit bien le string associer mais les autres prenne le dernier string envoyer dans l’intent !
    vue que je fait une nouvelle requette dans une BDD en fonction du string envoyer ba du coup j’affiche les bonne donné dans le premier onglet mais les autre reprénne les infos du dernier !!
    comment je peux faire passé une variable string différente à chaque onglet ?

  • http://www.ace-art.fr/wordpress Acesyde

    Il faut recréer un Intent de A-Z, il doit garder l’intent en mémoire ;)

  • fru

    Bonjour
    Excellent tuto, mais j’ai un probleme
    Pourrait tu regarder? 

  • http://www.ace-art.fr/wordpress Acesyde

    Je n’ai pas beaucoup de temps en ce moment, mais tu peux toujours tenter.

  • http://www.facebook.com/people/Zakaria-Max/1171084731 Zakaria Max

    bjr a tous je suis un debutant android je veut faire une application
    elle consiste a crée 3 bouton qui affiche 3 liste differente chaque
    ellement de ces liste affiche une image reference dans une base de
    donnée prés etablit avec sqlite je suis bloque au niveau de comment
    relier le bouton a la liste et relier les element de la liste a la base
    de donnée :-(((((((((((

    slv aider moi c pour mon memoire (license)

    merci d’avance :-)

  • Phoebus Du Flal

    Bonjour
    Sur la première image de votre exemple vous montrez des liens (nouveau contact)
    Quel code mettre pour traiter le clic sur ce lien ou même un bouton.
    Merci pour vos tutos.
    Cordialement’
    Phoebus.

  • http://www.ace-art.fr/wordpress Acesyde

    Bonjour Phoebus,

    L’écran que tu vois est celui du téléphone sous Android 1.6 et non une de mes créations.

    Regarde dans la dernière réponse de cette adresse ça devrait t’aider

    http://stackoverflow.com/questions/1895206/how-can-i-launch-the-add-contact-activity-in-android 

  • Vivien-57

    Salut.

    Tuto super encore une fois, tout marche nickel, j’ai un petit truc qui change avec toi c’est le style des onglets (ils ont pas vraiment la même forme, j’ai pas d’espace entre les deux, enfin pas vraiment la même allure les onglets).

    Ça vient de la version Android tu penses ? (J’ai développé sous 2.1 moi)Merci

  • http://www.ace-art.fr/wordpress Acesyde

    Oui la version 2.1 a un style différent de la 1.6 et encore plus sur la 3.0 et 4.0 :)

  • Vivien-57

    J’ai un petit problème avec les tabhost.

    En effet quand je fait ton tutoriel ça marche nickel mais quand j’essai de l’insérer dans l’un de mes projets j’ai une FC. Je t’explique ce que j’essai de faire.

    J’ai une activité principal ou je une listeView perso, quand je clique sur un element de la liste view perso, j’aimerai atterrir dans une autre activité ou là j’ai une activité avec un tabhost. Hors ça ne marche pas. 

    Aurais-tu une idée ?

    Pourtant j’ai bien trois activité, ma principale, et les deux suivantes correspondant au tabHost que tu décris dans ce tutos.

    Merci d’avance,

    Vivien

  • http://www.ace-art.fr/wordpress Acesyde

    As tu bien déclarer tes activités dans l’androidmanifest.xml ?

  • Vivien-57

    Oui oui j’ai fait. 

    Je ne comprend pas pourquoi ça ne fonctionne pas

  • Vivien-57

    Voici l’erreur que j’obtiens dans le LogCat

    http://www.restomaniak.com/media/ErreutLogCat.PNG (screen de l’erreur)

  • Vivien-57

    J’ai résolu le problème, j’avais bien oublié de déclarer dans l’androidmanifest.xml.

    Merci beaucoup pour ta réponse rapide.

    Vivien

  • Vivien-57

    Juste une autre question, comment je peux faire pour avoir une activité par onglet et donc un fichier xml par onglet ?

    Car avec ta méthode je n’arrive pas bien à voir comment gérér l’interface graphique de chaque onglet (sachant que j’en ai 3)
    Merci

    Vivien

  • Vivien-57

    C’est bon j’ai réussi également.

    Merci encore.

    Vivien