Académique Documents
Professionnel Documents
Culture Documents
Par AndroWiiid
www.siteduzero.com
2/79
Sommaire
Sommaire ........................................................................................................................................... 2 Lire aussi ............................................................................................................................................ 1 Aller plus loin dans le dveloppement Android ................................................................................... 3
Bonjour amis Zros, .......................................................................................................................................................... 3
ListFragment ................................................................................................................................................................... 16
Utilisation simple des listes ....................................................................................................................................................................................... Dclarer sa liste dans des fichiers XML .................................................................................................................................................................... Cration de la ListFragment ...................................................................................................................................................................................... Intgrer une vue personnalise ................................................................................................................................................................................. Crer une vue personnalise .................................................................................................................................................................................... Crer son adaptateur ................................................................................................................................................................................................ Vers des listes dynamiques ....................................................................................................................................................................................... Modification de l'adaptateur ...................................................................................................................................................................................... Paramtriser son application ..................................................................................................................................................................................... Dfinir ses prfrences ............................................................................................................................................................................................. Crer son fragment avec son activit ........................................................................................................................................................................ Affiner ses paramtres avec les en-ttes .................................................................................................................................................................. Dfinir les en-ttes .................................................................................................................................................................................................... Attacher une activit ............................................................................................................................................................................................... Lire les prfrences ................................................................................................................................................................................................... 16 16 17 18 18 20 22 22 28 28 30 31 32 33 34
PreferenceFragment ....................................................................................................................................................... 28
DialogFragment ............................................................................................................................................................... 36
Crer un DIalogFragment .......................................................................................................................................................................................... 36 Crer un AlertDialog .................................................................................................................................................................................................. 37 Afficher une boite de dialogue ................................................................................................................................................................................... 39 Correction .................................................................................................................................................................................................................. 40
www.siteduzero.com
Sommaire
3/79
Par
AndroWiiid
Mise jour : 04/01/2013 Difficult : Difficile 245 visites depuis 7 jours, class 323/798
www.siteduzero.com
4/79
Fragment
Introduction aux fragments Les fragments, kzako ?
La notion de fragment est souvent confuse pour les dbutants et pas toujours bien comprise par ceux qui commencent programmer assez rgulirement sur la plateforme Android. Les fragments sont mi-chemin entre l'activit et la vue ; c'est--dire qu'il ne s'agit ni de l'un, ni de l'autre mais qu'ils sont troitement lis. V otre fragment consiste dfinir un morceau d'interface que vous pourrez attacher plusieurs endroits, sur des activits. Par exemple, dans le cas o vous dsirez rendre compatible votre application sur smartphone et sur tablette, vous n'aurez pas spcialement envie avoir la mme interface. La taille d'cran des tablettes tant largement plus grande que celles des smartphones, il serait dommage de ne pas en profiter. L'ide consiste de dfinir des fragments que vous afficherez un un sur un smartphone et plusieurs sur tablette. Si vous avez une liste de news (par hasard ? ). Sur votre smartphone, vous afficherez cette liste et une fois que l'utilisateur aura effectu une pression sur l'un des items de la liste, vous lancerez un autre cran avec les dtails de la news slectionne. Quant la version tablette, vous afficherez la liste des news gauche et directement droite les dtails de la news slectionne, sans changer d'cran. Ce genre de chose est possible grce aux fragments !
www.siteduzero.com
5/79
dveloppeurs Android
La bibliothque de compatibilit
C'est bien beau n'est-ce pas ? Un monde o vous pouvez librement placer des fragments aux endroits que vous dsirez pour optimiser vos applications sur le plus d'appareil possible. Malheureusement, ce n'est pas si simple. Au dbut, Android tait ddi uniquement aux smartphones ; c'est--dire des crans de moins de 4 pouces (les smartphones de plus de 4 pouces ne sont
www.siteduzero.com
6/79
arrivs que trs rcemment l'heure o j'cris ces lignes). Par aprs, Google a tendu son systme aux tablettes avec la version 3 (les versions 2 et moins taient donc destins aux smartphones) et la version 4 qui unifie les 2 types. Aujourd'hui, on commence de plus en plus voir des TV avec Android comme systme. Il est tout fait possible de dvelopper pour ce genre d'appareil mais les bonnes pratiques d'ergonomie sont encore un peu vague. C'est pourquoi nous ne verrons pas d'exemple concret pour les TV mais les techniques que vous apprendrez dans ce tutoriel vous permettront d'en dvelopper. C'est avec cette version 3, HoneyComb, qu'est apparu les fragments. Techniquement, ce composant (et les autres que nous verrons dans la suite de cette premire partie) n'est pas disponible en dessous de cette version. Comment pouvons-nous donc dvelopper notre application sans devoir crer deux projets (un pour les versions 2 et antrieur et un autre pour la version 3 et suprieur) ? Je vous ai dj dit que Google tait une boite formidable ? Maintenant, je vous le dis. Google est une boite formidable ! Ils ont dvelopp une librairie de compatibilit qui vous permettra d'utiliser une trs grande partie des fonctionnalits disponibles partir de la version 3 d'Android ds la version 2.1. Soit regrouper environ 95% du march des appareils tournant avec Android. Nous apprendrons l'utiliser et aller plus loin grce un projet communautaire de compatibilit que nous verrons plus loin dans ce tutoriel.
www.siteduzero.com
7/79
Nous dsrialisons ce fichier XML d'affichage dans un fragment que nous nommerons FixeFragment : Code : Java package com.siteduzero.android.fragments.fixe; import import import import import android.os.Bundle; android.support.v4.app.Fragment; android.view.LayoutInflater; android.view.View; android.view.ViewGroup;
import com.siteduzero.android.R; public class FixeFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_fixe, container, false); } }
V ous remarquerez que je spcifie exprs la dfinition du paquetage et les imports. C'est une chose importante dans les fragments, cela sera une habitude prise dans ce tutoriel pour que vous ne soyez jamais perdu. V ous pouvez vous rendre compte de la simplicit dconcertante de la cration d'un fragment. Son utilisation est tout aussi simple lorsque vous l'attachez fixement une activit. Dans chaque activit, nous allons crer un autre fichier XML d'affichage, que nous nommerons activity_fragment_fixe, et dans lequel nous allons dclarer un widget Fragment qui spcifie dans son attribut android:name notre FixeFragment. Code : XML <?xml version="1.0" encoding="utf-8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:name="com.siteduzero.android.fragments.fixe.FixeFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
Dans le code de l'activit, FixeActivity , il nous suffit simplement de dsrialiser le fichier XML d'affichage que nous venons de crer pour attacher notre Fragment et d'tendre la classe FragmentActivity la place de Activity pour notifier Android que nous utilisons des Fragment. Code : Java package com.siteduzero.android.fragments.fixe; import com.siteduzero.android.R; import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class FixeActivity extends FragmentActivity { @Override protected void onCreate(Bundle arg0) { super.onCreate(arg0); setContentView(R.layout.activity_fragment_fixe);
www.siteduzero.com
8/79
Qu'est ce que nous pouvons en dire ? V ous pouvez vous rendre compte que l'activit est vide, peu importe ce que vous placez dans un fragment. C'est l'une des forces de l'utilisation des fragments. Habituellement, les activits jouent le rle des contrleurs dans une architecture MVC (patron architectural sur lequel Android se base dans le dveloppement d'application). Dans notre cas, les fragments joueront le rle de contrleurs pour les vues qu'ils instancient. Cela permet de maintenir plus aisment le code et de sparer les responsabilits entre diffrentes classes.
FixeActivity
www.siteduzero.com
9/79
Correction
V ous avez russi trouver quelque chose ? Si vous tes parvenu un rsultat similaire au mien, c'est dj pas mal. Si vous avez la mme solution que moi, c'est encore mieux. Pourquoi ? Simplement parce que la solution la plus simple pour parvenir mon rsultat est de crer un nouveau fichier XML d'affichage du mme nom que celui de l'activit qui se trouve dans le dossier layout mais dans le layout-land et en dfinissant les deux Fragment dans ce fichier. Le systme se rendra automatiquement dans ce dossier pour rcuprer le bon fichier XML et tout sera fait automatiquement ! Code : XML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <fragment android:name="com.siteduzero.android.fragments.fixe.FixeFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> <fragment android:name="com.siteduzero.android.fragments.fixe.FixeFragment"
www.siteduzero.com
10/79
www.siteduzero.com
11/79
Chaque transaction doit appeler la mthode commit() pour voir ses oprations s'effectuer. En cas contraire, aucune erreur ne sera lance mais rien ne se passera.
Rsultat final
Mais attends une seconde. C'est bien beau tout a mais je fais comment pour appeler la mthode private void showFragment(final Fragment fragment) lorsque je clique sur mes boutons ? Mes fragments ne connaissent pas forcment l'activit prcise dans lequel il se trouve. V ous n'avez pas tord mais Google a apport une rponse ce lger problme. L'un des attributs que vous pouvez donner vos boutons est le suivant : android:onClick. La valeur que vous donnez cet attribut vous oblige implmenter une mthode du mme nom dans l'activit dans laquelle il est dsrialis. Du coup, dans le fichier XML d'affichage de fragment 1 et 2, nous avons donn les valeurs respective goToFragment2 et goToFragment1. Par consquent, nous implmentons notre activit de la manire suivante : Code : Java public class DynamicActivity extends FragmentActivity {
www.siteduzero.com
12/79
private void setupFragments() { final FragmentManager fm = getSupportFragmentManager(); this.mDynamic1Fragment = (Dynamic1Fragment) fm .findFragmentByTag(Dynamic1Fragment.TAG); if (this.mDynamic1Fragment == null) { this.mDynamic1Fragment = new Dynamic1Fragment(); } this.mDynamic2Fragment = (Dynamic2Fragment) fm .findFragmentByTag(Dynamic2Fragment.TAG); if (this.mDynamic2Fragment == null) { this.mDynamic2Fragment = new Dynamic2Fragment(); }
private void showFragment(final Fragment fragment) { if (fragment == null) return; final FragmentManager fm = getSupportFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); // We can also animate the changing of fragment ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right); ft.replace(R.id.frameLayoutListView, fragment); } ft.commit();
Si vous excutez notre application, lorsque vous cliquez sur l'un des boutons des fragments, le fragment courant s'animera en se dplaant vers la droite pour laisser place notre second fragment. V ous constatez qu'en plus de pouvoir facilement de fragment, il est simple d'effectuer quelques animations sur le changement.
www.siteduzero.com
13/79
DynamicActivity
Correction
Code : Java
www.siteduzero.com
14/79
import com.siteduzero.android.R; public class DynamicActivity extends FragmentActivity { private String mFragment; private Dynamic1Fragment mDynamic1Fragment; private Dynamic2Fragment mDynamic2Fragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment_dynamic); if (savedInstanceState != null) mFragment = savedInstanceState.getString("fragment"); else mFragment = getIntent().getStringExtra("fragment"); setupFragments(); if (mFragment != null) { if (mFragment.equals("Dynamic1Fragment")) { showFragment(this.mDynamic1Fragment); } else if (mFragment.equals("Dynamic2Fragment")) { showFragment(this.mDynamic2Fragment); } }
@Override protected void onSaveInstanceState(Bundle outState) { outState.putString("fragment", mFragment != null ? mFragment : ""); super.onSaveInstanceState(outState); } private void setupFragments() { final FragmentManager fm = getSupportFragmentManager(); this.mDynamic1Fragment = (Dynamic1Fragment) fm .findFragmentByTag(Dynamic1Fragment.TAG); if (this.mDynamic1Fragment == null) { this.mDynamic1Fragment = new Dynamic1Fragment(); } this.mDynamic2Fragment = (Dynamic2Fragment) fm .findFragmentByTag(Dynamic2Fragment.TAG); if (this.mDynamic2Fragment == null) { this.mDynamic2Fragment = new Dynamic2Fragment(); }
private void showFragment(final Fragment fragment) { if (fragment == null) return; final FragmentManager fm = getSupportFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); // We can also animate the changing of fragment ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
www.siteduzero.com
15/79
www.siteduzero.com
16/79
ListFragment
Le widget ListView est sans aucun doute l'un des composants graphiques les plus utiliss dans les applications Android, au mme titre que le ViewPager ou le GridView. Il permet d'afficher facilement des informations l'un la suite de l'autre verticalement avec des vues personnalises ou non. Dans un premier temps, nous allons voir comment utiliser ce composant ml la puissance des fragments. Nous compliquerons rapidement les choses en intgrant des vues personnalises chaque item de nos listes. Pour finir, nous rendrons l'affichage de cette liste dynamique avec l'apparition de vues diffrentes.
www.siteduzero.com
17/79
Cration de la ListFragment
A la diffrence du chapitre prcdent, notre fragment ne va pas tendre la classe Fragment mais ListFragment qui est le parfait quivalent de la classe ListActivity. De la mme manire que les fragments basiques, nous allons dsrialiser notre fichier XML d'affichage dans sa mthode public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) (chose qui n'est pas obligatoire. V ous pouvez ne pas vouloir afficher quelque chose lorsque la liste est vide. Dans ce cas, il vous suffit de ne crer aucun fichier XML et de ne pas redfinir la mthode prcdemment cite). De la mme manire qu'une ListActivity, nous devons rcuprer notre liste pour lui attacher un adaptateur (que nous ne crerons pas pour le moment). L'unique subtilit dans ce cas prsent est la mthode redfinir. En effet, nous aurons accs notre liste qu'une fois l'activit dans laquelle le fragment est hberg sera construite. Nous faisons toutes les manipulations destines la gestion de la liste dans la mthode public void onActivityCreated(Bundle savedInstanceState). Ce qui nous donne le code et le rsultat suivant : Code : Java package com.siteduzero.android.lists; import com.siteduzero.android.R; import import import import import import android.os.Bundle; android.support.v4.app.ListFragment; android.view.LayoutInflater; android.view.View; android.view.ViewGroup; android.widget.ArrayAdapter;
public class SimpleListViewFragment extends ListFragment { public static final String TAG = "ListViewFragment"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_listview, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); String[] items = getResources().getStringArray(R.array.list_examples); ArrayAdapter<String> aa = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, items); setListAdapter(aa);
www.siteduzero.com
18/79
www.siteduzero.com
19/79
Pour rester simple, notre classe Java, qui va dsrialiser notre fichier XML d'affichage, redfiniera simplement les constructeurs ncessaires pour appeler la super classe (LinearLayout) et offrira une mthode notre adaptateur pour attacher du texte notre TextView. Ainsi, nous obtenons le code suivant : Code : Java package com.siteduzero.android.lists; import com.siteduzero.android.R; import import import import android.content.Context; android.util.AttributeSet; android.widget.LinearLayout; android.widget.TextView;
public class CustomListViewView extends LinearLayout { private TextView mTextView; public CustomListViewView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public CustomListViewView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomListViewView(Context context) { super(context); init(); } private void init() { inflate(getContext(), R.layout.view_custom_listview, this); mTextView = (TextView) findViewById(R.id.textView); } public void bind(int text) {
www.siteduzero.com
20/79
public class CustomListViewAdapter extends BaseAdapter { private List<Integer> mModel = new ArrayList<Integer>(); private Context mContext; public CustomListViewAdapter(Context context) { mContext = context; } @Override public int getCount() { return mModel.size(); } @Override public Integer getItem(int position) { return mModel.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { CustomListViewView v = null; // Notre vue n'a pas encore t construite, nous le faisons if (convertView == null) { v = new CustomListViewView(mContext); } // Notre vue peut tre rcupre, nous le faisons else {
www.siteduzero.com
21/79
Notre fragment sera exactement identique au prcdent sous-chapitre l'exception prs que nous n'utilisons plus ArrayAdapter mais notre propre adaptateur (CustomListViewAdapter dans mon cas). V ous devriez alors avoir le mme rsultat que moi avec une belle fluidit puisque notre adaptateur est optimis au niveau de la gestion de la mmoire.
www.siteduzero.com
22/79
Modification de l'adaptateur
Le but de notre nouveau adaptateur est de construire plusieurs types de vues avec une seule mthode (je vous laisse deviner laquelle ). Pour cet exemple, nous construisons deux vues que je nommerai DynamicHeaderListViewView et
www.siteduzero.com
23/79
DynamicBodyListViewView. La premire affiche une image gauche et du texte droite, la seconde affiche simplement du texte (comme la vue pour le sous-chapitre prcdent). Je vous laisse le bon soin de crer ses vues comme nous l'avons fait prcdemment. Cela ne devrait pas vous posez de problme. Le vritable changement se situe au niveau de notre adaptateur. Nous tendrons toujours BaseAdapter mais nous allons redfinir deux mthodes supplmentaires qui sont facultatives (j'entends par l qu'il n'est pas ncessaire de toujours les redfinir, seulement quand cela est ncessaire) : public int getViewTypeCount() et public int getItemViewType(int position). A quoi servent ces mthodes ? La premire nous demande combien de vues diffrentes seront prsentes dans notre liste. La seconde nous demande le type de vues pour la position courante dans la liste. Pour pouvoir complter ces mthodes, nous aurons besoin de constantes reprsentants les types de vues et une liste faisant correspondre chaque ligne de la liste avec son type associ. Si nous continuons notre exemple, avec le header et le body , nous aurons quelque chose qui ressemble ceci : Code : Java public class DynamicListViewAdapter extends BaseAdapter { private static final int TYPE_HEADER = 0; private static final int TYPE_BODY = 1; private static final int TYPE_MAX = 2; private List<Integer> mTypes = new ArrayList<Integer>(); // Autres attributs @Override public int getViewTypeCount() { return TYPE_MAX; } @Override public int getItemViewType(int position) { return mTypes.get(position); } } // Autres mthodes
La mise en place est aussi simple que cela. Il va maintenant falloir remplir la liste des types avec les lignes de la liste. Cela se fait naturellement dans les mthodes d'attachement. Nous en aurons deux : l'une pour l'en-tte de la liste et une seconde pour le corps de la liste. La premire mthode prend en paramtre un modle qui se trouve tre une classe confectionn par mes soins avec seulement 2 attributs reprsentant une image et un texte. La seconde mthode est identique la mthode vue au souschapitre prcdent, elle prendra une liste de chanes de caractres. Pour chacune de ces mthodes, nous ajouterons au fur et mesure les types dans la liste des types. Cela nous dera quelque chose comme ceci : Code : Java public class DynamicListViewAdapter extends BaseAdapter { // Autres attributs et mthodes public void bindHeader(DynamicListViewModel model) { mModelHeader = model; mTypes.add(TYPE_HEADER); } public void bindBody(List<Integer> model) { mModelBody = model; for (int i = 0; i < model.size(); i++) { mTypes.add(TYPE_BODY); } }
www.siteduzero.com
24/79
Nous avons aussi besoin de retoucher un peu nos anciennes mthodes. La taille de notre liste ne correspond plus la taille de notre liste de donnes. Il faut donc prvoir qu'un en-tte (ou pas) soit plac quelque part dans notre liste. Ainsi, nous modifions nos mthodes de la manire suivante : Code : Java public class DynamicListViewAdapter extends BaseAdapter { // Autres attributs et mthodes @Override public int getCount() { if (mModelHeader == null) return mModelBody.size(); return 1 + mModelBody.size(); } @Override public Object getItem(int position) { int type = getItemViewType(position); return type == TYPE_HEADER ? mModelHeader : mModelBody .get(position - 1); } } // Autres mthodes
Pour finir, nous avons notre mthode public View getView(int position, View convertView, ViewGroup parent) sur laquelle je vais vous laisser cogiter. V ous disposez de toutes les mthodes ncessaires pour mener bien sa confection. Si vous avez bien compris l'exemple prcdent avec une seule vue personnalise pour toute la liste, vous ne devriez pas avoir de mal en faire de mme pour plusieurs vues personnalises. Pensez simplement que les mthodes que nous avons redfinies ne sont sans doute pas l pour rien. Bien sr, ma solution se trouve cache ci-dessous. Secret (cliquez pour afficher) Code : Java package com.siteduzero.android.lists; import java.util.ArrayList; import java.util.List; import import import import android.content.Context; android.view.View; android.view.ViewGroup; android.widget.BaseAdapter;
public class DynamicListViewAdapter extends BaseAdapter { private static final int TYPE_HEADER = 0; private static final int TYPE_BODY = 1; private static final int TYPE_MAX = 2; private List<Integer> mTypes = new ArrayList<Integer>(); private DynamicListViewModel mModelHeader = null; private List<Integer> mModelBody = new ArrayList<Integer>(); private Context mContext; public DynamicListViewAdapter(Context context) { mContext = context; } @Override public int getViewTypeCount() { return TYPE_MAX; } @Override
www.siteduzero.com
25/79
www.siteduzero.com
26/79
Il n'en faut pas plus pour concevoir une liste dynamique. Il vous suffit ensuite d'intgrer ce nouvel adaptateur votre activit, en n'oubliant pas d'appeler les mthodes d'attachement pour remplir votre liste et vous devriez obtenir un rsultat similaire au mien :
www.siteduzero.com
27/79
www.siteduzero.com
28/79
PreferenceFragment
Depuis la version 3, Android met disposition des dveloppeurs des outils permettant de paramtriser facilement son application. En quoi consiste cette paramtrisation ? C'est simple. Il s'agit ni plus ni moins que des donnes partages dans toute l'application (que vous avez dj certainement utilis) mais intgrer dans une conception toute fait. Nous confectionnerons des fragments (ou des activits) qui auront comme seul objectif l'affichage des paramtres de la mme manire que ceux de votre smartphone. Cela va vous facilitez la vie mais je vous met en garde sur une petite chose. Nous utilisons depuis le dbut de ce tutoriel la bibliothque de compatibilit dvelopp par Google. Les prfrences ont galement t intgres dans cette bibliothque mais n'est pas trs performante (ou du moins, pas une grande chelle). Parce que le code est quand mme assez diffrent et pour ne pas tre limit, nous ne l'utiliserons pas pour ce chapitre. Mais sachez qu'il est possible de l'utiliser. Il faudra juste se renseigner un peu sur la faon de s'y prendre.
www.siteduzero.com
29/79
www.siteduzero.com
30/79
www.siteduzero.com
31/79
www.siteduzero.com
32/79
smartphone
www.siteduzero.com
33/79
www.siteduzero.com
34/79
public void onCreate(Bundle savedInstanceState) comme le ferait toutes les autres activits. A la place, nous devrons redfinir la mthode public void onBuildHeaders(List<Header> target) pour y appeler la mthode suivante : public void loadHeadersFromResource (int resid, List<PreferenceActivity.Header> target). Cette mthode s'attend recevoir l'identifiant de la ressource des dclarations de vos en-ttes et la cible donn en paramtre votre mthode. En toute simplicit, nous arrivons au code suivant : Code : Java package com.siteduzero.android.settings; import java.util.List; import android.preference.PreferenceActivity; import com.siteduzero.android.R; public class SettingsActivity extends PreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.header_preferences, target); } }
www.siteduzero.com
35/79
www.siteduzero.com
36/79
DialogFragment
Nous allons aborder la dernire notion utilisant les fragments partir de la version 3 d'Android, les DialogFragment. Ce composant nous permettra d'afficher une boite de dialogue l'utilisateur de manire beaucoup plus souple et plus complet que vous auriez pu le faire avec les anciens composants des versions infrieurs la 3.
Crer un DIalogFragment
V ous avez sans doute dj utiliser des AlertDialog ou des Dialog (surtout si vous avez lu le tutoriel d'Applidore). L'ide est de r-utiliser ce type de composant mais en lui attachant des fragments. C'est une pratique qui vous permettra de concevoir des boites de dialogue infiniment plus complexe et plus puissante que vos anciennes boites de dialogue. DialogFragment servira de conteneur notre fragment pour le transformer en boite de dialogue et ainsi fournir le style et la structure de la boite. Cette classe fournit tous les contrles ncessaires pour crer la boite et grer son apparence. Chose que nous apprendrons faire tout au long de ce chapitre ainsi que l'intgration de builder pour un autre type de boite. Pour commencer, nous allons procder comme chaque cration d'un type de fragment ; c'est--dire que nous allons tendre notre classe DialogFragment et redfinir un certains nombre de mthodes utiles l'intgration de notre fragment dans la boite et sa gestion. Pour ce faire, nous allons redfinir et dfinir les 2 mthodes suivantes : public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) : Pour dsrialiser le fichier XML reprsentant notre fragment et pour donner un titre notre boite de dialogue (ce dernier tant optionnel). public static MyDialogFragment newInstance() : Je reviendrais dans la seconde partie de ce tutoriel sur ce type de mthode mais sachez qu'elle nous permet d'encapsuler la cration de notre fragment et d'en connaitre des potentielles donnes. Ne vous tracassez pas la tte avec a maintenant, vous comprendrez bien assez tt son utilit. Nous obtenons donc le rsultat suivant : Code : Java package com.siteduzero.android.dialog; import import import import import import import android.os.Bundle; android.support.v4.app.DialogFragment; android.view.LayoutInflater; android.view.View; android.view.View.OnClickListener; android.view.ViewGroup; android.widget.Button;
import com.siteduzero.android.R; public class MyDialogFragment extends DialogFragment { public static MyDialogFragment newInstance(int title) { MyDialogFragment dialog = new MyDialogFragment(); Bundle args = new Bundle(); args.putInt("title", title); dialog.setArguments(args); return dialog; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_dialog, container, false); Button button = (Button) v.findViewById(R.id.buttonShow); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { ((DialogActivity) getActivity()) .showDialogType(DialogActivity.TYPE_ALERT_DIALOG); } }); getDialog().setTitle(getArguments().getInt("title"));
www.siteduzero.com
37/79
Chez moi (vous n'aurez pas le mme rsultat si le fichier XML est diffrent), le rsultat final intgr dans une FragmentActivity donnera le rsultat suivant :
dialogue DialogFragment
Crer un AlertDialog
V ous tes cens savoir comment crer un AlertDialog. Je ne rentrerais donc pas dans les dtails en ce qui concerne sa cration mais beaucoup plus en ce qui concerne son intgration dans un fragment. En fait, c'est vraiment trs semblable au
www.siteduzero.com
38/79
DialogFragment et vous devrez avoir une petite ide de la manire de s'y prendre avec les connaissances que je viens de vous enseigner et vos connaissances prcdentes sur sa simple cration dans une Activity. Bien entendu, ce n'est pas exactement la mme chose. Nous n'allons pas devoir redfinir la mthode public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) mais public Dialog onCreateDialog(Bundle savedInstanceState). A partir de l, il nous suffit de retourner une AlertDialog avec l'aide d'un builder. La redfinition de la mthode donnera quelque chose comme : Code : Java @Override public Dialog onCreateDialog(Bundle savedInstanceState) { int title = getArguments().getInt("title"); return new AlertDialog.Builder(getActivity()) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(title) .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { ((DialogActivity) getActivity()) .doNegativeClick(); } }) .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { ((DialogActivity) getActivity()) .doPositiveClick(); } }).create();
N'oubliez pas d'implmenter la mthode static pour crer une instance comme nous l'avons fait avec DialogFragment. Ainsi, nous obtenons le rsultat suivant :
www.siteduzero.com
39/79
dialogue AlertDialog
www.siteduzero.com
40/79
destin l'affichage de l'AlertDialog. public void showDialogFragment(View v) : Appel au clique de l'utilisateur sur le bouton de notre activit destin l'affichage de DialogFragment. protected void showDialogType(int type) : Pour switcher dynamiquement entre les diffrentes botes de dialogue. Je vous laisse vos lignes de codes. V ous trouverez ma solution et son rsultat la suite de ce chapitre.
Correction
Code : Java package com.siteduzero.android.dialog; import import import import import import android.os.Bundle; android.support.v4.app.DialogFragment; android.support.v4.app.Fragment; android.support.v4.app.FragmentActivity; android.support.v4.app.FragmentTransaction; android.view.View;
import com.siteduzero.android.R; import com.siteduzero.android.dialog.alert.MyAlertDialog; public class DialogActivity extends FragmentActivity { public static final int TYPE_DIALOG_FRAGMENT = 1; public static final int TYPE_ALERT_DIALOG = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dialog); } protected void showDialogType(int type) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog"); if (prev != null) { ft.remove(prev); } ft.addToBackStack(null); DialogFragment newFragment = null; switch (type) { case TYPE_DIALOG_FRAGMENT: newFragment = MyDialogFragment .newInstance(R.string.title_fragment_dialog); break; case TYPE_ALERT_DIALOG: newFragment = MyAlertDialog .newInstance(R.string.title_fragment_dialog_alert); break; } newFragment.show(ft, "dialog");
public void showDialogFragment(View v) { showDialogType(TYPE_DIALOG_FRAGMENT); } public void showAlertDialog(View v) { showDialogType(TYPE_ALERT_DIALOG); } public void doPositiveClick() { // TODO Do something
www.siteduzero.com
41/79
www.siteduzero.com
42/79
Intgrer un menu
J'ai une bonne nouvelle pour vous, intgrer un menu dans une barre d'action est extrmement simple. Comme vous tes cens savoir comment crer des menus (sinon, je vous renvoie sur le tutoriel d'Apollidore sur les gestion des menus), il nous faudra que quelques modifications faire dans le fichier XML, c'est tout ! En effet, le systme dtectera automatiquement que vous lancez votre application sur un systme avec une version 3 ou suprieur d'Android et l'intgrera par dfaut. C'est plutt pratique ! V oici ce que nous allons faire : Nous allons crer un menu avec 4 items qui auront un identifiant, un titre et une icone. Cependant, nous allons rajouter une notion trs importante dans ces nouveaux menus, son affichage. En effet, un nouvel attribut est utilisable dans ces menus android:showAsAction. Cet attribut peut prendre une ou plusieurs valeurs parmi cette liste : ifRoom : Affichera l'item dans la barre d'action uniquement s'il y a encore de la place. withText : Affichera le texte du menu si le tlphone se trouve en mode paysage. never : N'affichera jamais l'item dans la barre d'action. always : Affichera l'item dans la barre d'action dans tous les cas. collapseActionView : Nous reviendrons sur cet attribut un peu plus tard dans ce chapitre. V ous devez savoir qu'il est possible de slectionner plusieurs des valeurs grce au pipeline | . Bien entendu, ne lui demander pas l'impossible, par exemple : never|always. Un exemple d'utilisation tout simple de nos 4 items se trouve la suite : Code : XML <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_search" android:actionViewClass="android.widget.SearchView" android:icon="@android:drawable/ic_menu_search" android:showAsAction="always" android:title="@string/menu_search"/> <item android:id="@+id/menu_add" android:icon="@android:drawable/ic_menu_add" android:showAsAction="ifRoom|withText" android:title="@string/menu_add"/> <item android:id="@+id/menu_save" android:icon="@android:drawable/ic_menu_save" android:showAsAction="ifRoom|withText" android:title="@string/menu_save"/>
www.siteduzero.com
43/79
Nous afficherons donc dans tous les cas le menu de recherche, s'il y a de la place et avec son texte le menu d'ajout et de sauvegarde et nous n'afficherons jamais le redimensionnement dans la barre d'action mais dans un menu part qui s'affichera l'extrme droite de la barre. Du ct Java, rien ne change ! V ous continuez redfinir la mthode public boolean onCreateOptionsMenu(Menu menu) pour dsrialiser votre menu et public boolean onOptionsItemSelected(MenuItem item) pour ragir au clique sur l'un ou l'autre item du menu. Ceci nous donnera alors le rsultat suivant :
www.siteduzero.com
44/79
Comme vous pouvez le constater, Android affiche notre item de recherche et d'ajout mais comme il n'y a plus de place pour la sauvegarde, il le place dans le sous menu accesible l'extrme droite de la barre.
Possibilits avances
La barre d'action, c'est sympa mais il est possible d'aller encore plus loin dans son utilisation. Nous ne verrons pas comment customiser cette barre. Cela prendrait un nouveau chapitre entier ce sujet et le design n'est pas le but de ce tutoriel. Cependant, si vous tes curieux ce sujet, Google a mis en place un site accessible via ce lien qui vous permettra de gnrer des styles tout faits. Il suffit alors de les intgrer vos projets. V ous devriez avoir les comptences pour le faire tout seul.
Barre de recherche
www.siteduzero.com
45/79
Dans un premier temps, nous allons voir comment rendre notre item, destin effectuer une recherche, mieux intgr notre barre d'action (et ainsi comprendre quoi servira la dernire valeur du nouvel attribut sur les items du menu). L'ide est la suivante : Lorsque nous cliquerons sur la loupe, un champ de recherche prendra toute la place de la barre d'action (cachant les autres items du menu au passage) et affichant le clavier pour permettre l'utilisateur d'effectuer sa recherche dans votre application. Pour ce faire, nous aurons besoin d'effectuer des changements la fois du ct de l'XML et du ct Java. Du ct XML, nous allons rajouter un nouvel attribut android:actionViewClass. Il nous permet de spcifier un layout ou un widget utiliser. Dans notre cas, nous allons utiliser un widget dj integr au systme que nous r-utilisons. Nous modifions aussi android:showAsAction en rajoutant la valeur collapseActionView pour rendre notre vue pliable dans l'item du menu et ainsi la dplie tout le long de notre barre lorsque nous cliquons dessus. Ainsi, nous obtenons : Code : XML <item android:id="@+id/menu_search" android:actionViewClass="android.widget.SearchView" android:icon="@android:drawable/ic_menu_search" android:showAsAction="ifRoom|collapseActionView" android:title="@string/menu_search"/>
La modification du ct Java n'est pas ncessaire puisque si vous testez l'application comme a, vous aurez l'effet escompt. Cependant, il est fort utile de connaitre un listener qui s'attache ce type de vue OnQueryTextListener. Ce listener vous demandera d'implmenter deux mthodes : public boolean onQueryTextSubmit(String query) pour rcuprer la chane de caractre que l'utilisateur aura rentr lorsqu'il aura envoy la requte. public boolean onQueryTextChange(String newText) pour rcuprer la chane de caractre en cours lorsque l'utilisateur rentre un nouveau caractre ou en supprime. Ainsi, nous devons rcuprer notre item lors de la dsrialisation de notre menu et lui attacher notre listener via sa mthode public void setOnQueryTextListener (SearchView.OnQueryTextListener listener). V ous obtiendrez un rsultat similaire celui-ci : Code : Java @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_actionbar, menu); // SearchView MenuItem itemSearch = menu.findItem(R.id.menu_search); mSearchView = (SearchView) itemSearch.getActionView(); mSearchView.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { Toast.makeText(getApplicationContext(), R.string.toast_search_submit, Toast.LENGTH_SHORT) .show(); return true; } @Override public boolean onQueryTextChange(String newText) { return false; } }); } return true;
www.siteduzero.com
46/79
la barre d'action
www.siteduzero.com
47/79
Ce que nous voulons est trs simple. Rcuprer l'item et lui demander quoi partager avec l'aide de la mthode public void setShareIntent (Intent shareIntent). Dans l'exemple qui suit, nous avons decider de partager simplement du texte mais cela aurait pu tre n'importe quoi d'autres qu'un Intent supporte (image, fichier, etc.). Nous obtenons alors la mthode suivante : Code : Java @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_actionbar, menu); // ShareActionProvider MenuItem itemProvider = menu.findItem(R.id.menu_share); mShareActionProvider = (ShareActionProvider) itemProvider.getActionProvider(); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "Message"); mShareActionProvider.setShareIntent(shareIntent); } return true;
www.siteduzero.com
48/79
Spliter le menu
V ous savez sans doute de quoi je parle, l'application de messagerie du systme Android l'utilise dans son application. L'ide est de sparer le menu de la barre d'action dans une nouvelle barre situ en bas de l'cran. Cela nous permettra de mettre plus d'item visible l'utilisateur et de dissocier la barre d'action du menu. En contre partie, nous perdons de la place sur l'cran. Sa mise en place est extrmement simple puisqu'il suffit de rajouter l'attribut et la valeur android:uiOptions="splitActionBarWhenNarrow" dans l'activit contenant le menu que vous voulez diviser dans le fichier Manifest.
www.siteduzero.com
49/79
barre d'action
Bouton home
Dernire petite chose, l'icone en haut gauche de votre cran peut galement servir comme un bouton. Il est gnralement utilis pour revenir en arrire (comme un bouton back) ou l'cran d'accueil de votre application (justement pour ne pas tre redondant au bouton back) mais vous pouvez l'utiliser comme bon vous semble. Je vous conseil quand mme de l'utiliser cet usage afin que les utilisateurs Android ne soient pas dbousolls lorsqu'ils utilisent votre application. Pour ce faire, vous devez rcuprer la barre d'action grce la mthode public ActionBar getActionBar() et apperler la mthode public abstract void setDisplayHomeAsUpEnabled (boolean showHomeAsUp)
www.siteduzero.com
50/79
dessus en lui donnant la valeur true. V otre icone aura alors une petite flche gauche de l'icone qui vous indiquera que vous pouvez cliquer dessus (voire les captures d'cran ci-dessus). Code : Java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true);
Un identifiant lui est automatiquement assign par le systme que vous pourrez tester dans la mthode public boolean onOptionsItemSelected(MenuItem item) et qui es R.id.home.
Menu contextuel
V ous vous rappelez des anciens menus contextuels ? Malheureusement, c'est une pratique qui peut encore tre utilise dans les applications actuelles mais qui ne sont pas du tout ergonomiques. V ous tes oblig de presser un certain temps sur un lment avec votre doigt pour voir apparaitre votre menu. Google a rflchi cette problmatique et a trouv une solution plutt lgante. Nous allons profiter de la barre d'action pour afficher un menu intermdiaire qui apparaitra quand bon vous semble (j'entends par l qu'il n'est pas ncessaire de rester appuy sur un lment pour faire apparaitre le menu). D'ailleurs, dans notre exemple, nous l'afficherons lorsque l'utilisateur cliquera sur un bouton pour bien diffrencier ce type de menu avec l'ancien mais sachez qu'il est toujours possible de le faire avec l'ancienne mthode. Nous dclarons un nouveau fichier XML destin tre notre menu intermdiaire. Nous le dclarons comme un menu normal, nous n'avons rien faire en plus de ce ct. Tout se jouera dans la partie Java. V ous tes maintenant cens savoir comment dclarer ce genre de choses, je vous laisse donc ce plaisir. Dans notre fichier XML d'affichage, nous dclarons un bouton avec un attribut android:onClick qui prendra la valeur changeContextual. Si vous ne connaissez pas cet attribut, il vous permet d'assigner une mthode de votre Activity votre bouton que vous avez spcifi. La mthode dsigne par cet attribut doit tre sous la sous la forme public void nomDeLaMethode(View view). Sinon, votre application plantera.
Nous voulons simplement afficher le menu contextuel, nous allons donc appeler la mthode public ActionMode startActionMode (ActionMode.Callback callback) sur l'activit. Cette mthode lancera l'affichage du menu grce au paramtre que vous lui donnez en paramtre. Ce paramtre prend une implmentation d'une interface Callback appartenant ActionMode. Son implmentation exige 4 mthodes redfinir : public boolean onActionItemClicked(ActionMode mode, MenuItem item) pour rcuprer l'item sur lequel l'utilisateur a cliqu. public boolean onCreateActionMode(ActionMode mode, Menu menu) pour dsrialiser votre fichier XML contenant votre menu. public void onDestroyActionMode(ActionMode mode) appel lorsque votre menu est dtruit (lorsqu'il n'est plus affich l'cran). public boolean onPrepareActionMode(ActionMode mode, Menu menu) appel lorsqu'on tente de rafraichir le menu avec une mthode invalidate. Pour rester simple, nous allons simplement donner une implmentation aux deux premires mthodes qui fonctionnent exactement comme les menus normaux ! Nous obtenons alors une Activity semble au code ci-dessous et au rsultat suivant : Code : Java package com.siteduzero.android.actionbar; import android.app.Activity; import android.os.Bundle; import android.view.ActionMode;
www.siteduzero.com
51/79
import com.siteduzero.android.R; public class ActionBarContextualActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contextual); } public void changeContextual(View view) { startActionMode(new ActionMode.Callback() { @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_trash: Toast.makeText(getApplicationContext(), R.string.toast_trash, Toast.LENGTH_SHORT).show(); return true; } return false; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_contextual, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } });
www.siteduzero.com
52/79
Mais alors, cela voudrait dire que nous pouvons crer plusieurs menus contextuels pour une seule classe ?
V ous avez tout compris. V ous pourriez crer plusieurs menus contextuels en fonction de la situation. C'est l'une des forces de ce type de menu et une excellente alternative l'ancienne manire de faire !
www.siteduzero.com
53/79
Je vous rappelle que static signifie que la mthode n'est pas directement attache aux instances que vous crez de la classe dans laquelle la mthode est retenue. Par exemple, vous pouvez donc y crer des instances de la classe dans laquelle vous tes. Maintenant, imaginons que nous voulons donner une chane de caractres notre Fragment pour l'afficher dans un TextView qu'il contient. L'ide est de crer un Bundle qui va contenir une chane de caractres avec une cl que nous dfinirons pour le rcuprer par la suite dans la cration de l'interface du fragment ; c'est--dire dans sa mthode public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState). Dans un premier temps, nous allons remplir notre mthode static pour attacher un Bundle notre fragment. Cela se fait trs simplement avec la mthode public void setArguments(Bundle args) : Code : Java public static DummyFragment newInstance(String chaine) { DummyFragment fragment = new DummyFragment(); Bundle args = new Bundle(); args.putString("KEY_STRING", chaine); fragment.setArguments(args); return fragment; }
C'est aussi simple que cela. Nous crer une instance de notre Fragment, on cre un bundle dans lequel nous placons notre chane de caractres, nous l'attachons notre Fragment et nous le renvoyons. Pour rcuprer ce Bundle, c'est tout aussi simple. Le setter des arguments de notre fragment possde galement un getter. Nous pouvons donc trs simplement rcuprer
www.siteduzero.com
54/79
le Bundle grce la mthode public final Bundle getArguments(). Ainsi, notre mthode public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) ressemblera : Code : Java @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); Bundle args = getArguments(); textView.setText(args.getString("KEY_STRING")); return textView; }
V ous l'avez sans doute remarqu mais je n'ai pas utilis de fichier XML d'affichage pour mon Fragment. L'XML est une pratique que j'encourage mais dans le cadre de cet exemple, pour rester simple, j'ai prfr crer dynamiquement un TextView pour afficher notre chane de caractres. C'est tout ! Grce cette mthode, vous crez vos fragments grce la mthode static et l'affichage de ce dernier, vous verrez la chane de caractres (ou n'importe quelle information que vous lui avez donn) l'cran.
Correction
Code : Java package com.siteduzero.android.viewpager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import com.siteduzero.android.R; public class ViewPagerAdapter extends FragmentPagerAdapter { public ViewPagerAdapter(FragmentManager fm) {
www.siteduzero.com
55/79
@Override public Fragment switch(pos) { case 1: return !"); case 2: return !"); case 3: return cran !"); } return null; }
getItem(int pos) { DummyFragment.newInstance("Je suis le premier cran DummyFragment.newInstance("Je suis le second cran DummyFragment.newInstance("Je suis le troisime
Activit du ViewPager
Nous avons notre Fragment, notre adaptateur, il nous manque plus que notre activit. Pour une fois, notre fichier XML d'affichage aura une petite particularit. Nous allons dclarer simplement un ViewPager sa racine mais pour des soucis de compatibilit, notre conteneur est galement redfini dans le projet v4 que nous utilisons depuis le dbut de ce tutoriel. Pour ce faire, le nom de l'lement sera accessible par le chemin android.support.v4.view et nous donnera donc la dclaration suivante : Code : XML <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" />
Du ct de notre Activity, c'est exactement pareil qu'avec les autres conteneurs. A la diffrence que nous n'tendrons pas Activity mais FragmentActivity. Cela nous donnera donc le code et le rsultat suivant : Code : Java package com.siteduzero.android.viewpager; import import import import android.app.FragmentTransaction; android.os.Bundle; android.support.v4.app.FragmentActivity; android.support.v4.view.ViewPager;
import com.siteduzero.android.R; public class ViewPagerActivity extends FragmentActivity { private ViewPagerAdapter mSectionsPagerAdapter; private ViewPager mViewPager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpager); // Set up the adapter. mSectionsPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
www.siteduzero.com
56/79
ViewPager
www.siteduzero.com
57/79
Navigation en tab
Pour indique que nous comptons utiliser les tabs de la barre d'action, nous devons rcuprer notre barre d'action et appeler dessus la mthode public abstract void setNavigationMode(int mode). Cette mthode prend en paramtre un mode qui se retrouve comme constante dans la classe ActionBar : NAVIGATION_MODE_STANDARD : Valeur par dfaut de votre barre d'action. Consiste afficher votre logo ou icone et le texte avec un sous titre optionnel dans la barre d'action. NAVIGATION_MODE_LIST : Change le titre prsent dans la barre d'action en une liste droulante que vous pouvez drouler lorsque vous cliquez dessus. NAVIGATION_MODE_TABS : V ous permettra d'utiliser des tabs dans votre barre d'action. Ainsi, dans notre mthode public void onCreate(Bundle savedInstanceState) de notre Activity, nous faisons la manipulation suivante : Code : Java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set up others things // Set up the action bar. final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); } // Set up others things
Modifier l'indicateur
Pour modifier l'indicateur en fonction de la page courante de l'utilisateur sur le ViewPager, nous allons devoir attacher un listener notre conteneur via la mthode public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener). Le lisener OnPageChangeListener impose d'implmenter 3 mthodes : public abstract void onPageScrollStateChanged(int state): Appel lorsque l'tat du dfilement change. public abstract void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) : Appel lorsque la page courante est en train d'tre modifi. public abstract void onPageSelected(int position) : Appel lorsqu'une nouvelle page est slectionne. La dernire mthode est celle qui nous intresse puisqu'elle nous indique la position dans laquelle nous nous trouvons dans le conteneur. Ainsi, nous pouvons appeler la mthode public abstract void setSelectedNavigationItem(int position) sur la barre d'action et obtenir le rsultat suivant : Code : Java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
www.siteduzero.com
58/79
V ous remarquez sans doute que je n'implmente pas les 3 mthodes. C'est simplement grce ViewPager.SimpleOnPageChangeListener qui est un listener alternatif qui me permet de redfinir uniquement les mthodes que je veux redfinir. C'est bien pratique mais il est ncessaire d'avoir une petite ide des mthodes accessibles.
Modifier la page
Pour finir, nous voulons faire l'inverse, nous voulons modifier la page courante du conteneur lorsque nous cliquons sur l'un des tabs de notre activit. Pour ce faire, nous devons faire plusieurs choses : A la dclaration de nos tabs, nous allons attacher chaque tab le mme listener qui va s'occuper de changer la page courante de notre ViewPager. Pour ce faire, nous allons implmenter au niveau de l'activit, la classe ActionBar.TabListener. Elle nous oblige alors implmenter 3 mthodes : public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) : Appel lorsqu'un tab n'est plus slectionn. public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) : Appel lorsqu'un tab est slectionn. public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) : Appel lorsqu'un tab est reslectionn. On implmentera donc la seconde mthode de la manire suivante : Code : Java @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { mViewPager.setCurrentItem(tab.getPosition()); }
Nous pouvons maintenant crer nos tabs grce trois mthodes que nous appellerons sur une instance de notre barre d'action : public abstract void addTab(ActionBar.Tab tab) : Mthode pour ajouter un tab l'activit. public abstract ActionBar.Tab newTab() : Mthode pour crer un tab. public abstract ActionBar.Tab setTabListener (ActionBar.TabListener listener) : Mthode pour attacher un listener notre tab. Nous utiliserons donc ces mthodes de la manire suivante : Code : Java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpager); // Set up other things // For each of the sections in the app, add a tab to the action bar.
www.siteduzero.com
59/79
actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)). } }
V ous avez sans doute remarqu la mthode public CharSequence getPageTitle(int position) appel sur notre adaptateur. Cette mthode est en fait une mthode optionnel implmenter qui nous permettra de contenir l' intelligence pour le choix du titre de nos pages. V ous n'tes pas oblig de recourir cette mthode, c'est juste un plus que je vous offre. Ceci nous donnera alors le rsultat suivant en mode portrait et paysage :
www.siteduzero.com
60/79
d'indicateur en portrait
www.siteduzero.com
61/79
www.siteduzero.com
62/79
Notifier l'utilisateur
Les notifications, cela ne devrait pas tre un nouveau concept. V ous en avez dj dvelopp et cela vous certainement bien servi dans vos applications. Cependant, la construction des notifications a chang depuis Android 3 et de nouvelles notifications sont apparus avec Android 4.1. Ce chapitre est donc destin uniquement vous enseignez comment construire ces nouvelles notifications sans parler de services et autres endroits o vous tes cens lancer vos notifications. Ces choses ont t abordes dans le tutoriel de Apollidore.
Basique
La cration de notifications se fait maintenant par l'intermdiaire d'un service systme, chose que vous devriez bien connatre puisqu'une grande partie des services du systme sont grs de cette manire. Il vous faudra donc en rcuprer une instance grce l'instruction suivante : Code : Java mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Maintenant que vous savez cela, nous pouvons commencer l'apprentissage de notre premire notification basique. Ce type de notification est la seule pouvant tre lance sur les terminaux Android 3 et plus. Aprs cela, tous les autres types plus complexes seront apparus avec la version 4.1 d'Android. Cependant, grce au projet de compatibilit v4 que nous utilisons constamment dans ce tutoriel, ce procd est accessible aux versions plus anciennes que la version 3. Par contre, les nouveaux concepts de la version 4.1 seront ignors si vous construisez ces types de notifications ; c'est--dire que vous pouvez construire des notifications complexes qui s'afficheront correctement sur la version 4.1 et suprieur mais qui paraitront comme de simples notifications sur les autres versions. C'est un bon compromis pour rester compatible avec les anciennes versions mais il faut garder cet aspect l'esprit. Dans un premier temps, nous aurons besoin d'un Builder spcifique aux notifications. Il est accessible par la classe Notification et s'initialise avec son constructeur en lui passant un contexte en paramtre : Code : Java Builder builder = new NotificationCompat.Builder(this);
A partir de cette instance, nous allons construire et rcuprer une instance de la classe Notification. Pour la construire, nous avons accs une petite srie de mthodes : public NotificationCompat.Builder votre notification. public NotificationCompat.Builder votre notification. public NotificationCompat.Builder notification. public NotificationCompat.Builder votre notification. setContentTitle(CharSequence title) : Donne un titre setContentText(CharSequence text) : Donne un texte setSmallIcon(int icon) : Donne une icne votre setWhen(long when) : Donne un timestamp pour l'affichage de
Ce n'est pas toutes les mthodes possibles disponibles partir d'Android 3, elles sont trop nombreuses et ce tutoriel n'est pas destin devenir une documentation. Si vous voulez en savoir plus, je vous renvoie sur la documentation Android. Aprs quoi, nous initialiserons les flags comme vous le faisiez avec les prcdentes notifications et nous la lanons grce la mthode public void notify(int id, Notification notification) sur notre service systme. Ce dernier prenant en paramtre l'identifiant de la notification et l'object comportant votre notification. Nous obtenons donc le code source et le rsultat suivant : Code : Java Builder builder = new NotificationCompat.Builder(this); Notification notification = builder .setContentTitle(getResources().getText(R.string.basic_title))
www.siteduzero.com
63/79
www.siteduzero.com
64/79
Grand texte
Abordons les nouvelles notifications avec un grand texte. Il faut savoir que vous tes limit en caractres si vous utilisez la mthode public NotificationCompat.Builder setContentText(CharSequence text). Elle s'affichera toujours sur une seule ligne uniquement. Ce n'est donc pas du tout optimis si, pour une raison X ou Y , vous dsirez crire plus. Cette nouvelle notification rgle le problme trs facilement et par l'intermdiaire d'une nouvelle classe, NotificationCompat.BigTextStyle, que vous devrez initialiser en passant un NotificationCompat.Builder en paramtre. V ous construisez donc votre builder de la mme manire que la notification basique, en omettant la mthode public NotificationCompat.Builder setContentText(CharSequence text) naturellement, et vous rcuprez un objet NotificationCompat.BigTextStyle en lui passant ce builder en paramtre de son constructeur. A partir de cet objet, vous pouvez appelez 3 mthodes diffrentes : public NotificationCompat.BigTextStyle bigText(CharSequence cs) : Afficher un grand texte pour votre notification. public NotificationCompat.BigTextStyle setBigContentTitle(CharSequence title) : Afficher un grand titre pour votre notification. public NotificationCompat.BigTextStyle setSummaryText(CharSequence cs) : Afficher un petit texte la fin de votre notification destin la rsum. Sachez que dans les 3 styles, les deux dernires mthodes seront toujours disponibles.
Une fois termin, vous appelez la mthode public Notification build () qui vous construira la notification que vous pourrez lancer. Ainsi, nous obtenons le code source et le rsultat suivant en utilisant simplement la premire des 3 mthodes disponibles pour NotificationCompat.BigTextStyle : Code : Java Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle(getResources().getText(R.string.big_text_title)) .setSmallIcon(R.drawable.ic_launcher); BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(builder); bigTextStyle.bigText(getResources().getText(R.string.big_text)); Notification notification = bigTextStyle.build(); notification.flags |= Notification.FLAG_AUTO_CANCEL; mNotificationManager.notify(0, notification);
www.siteduzero.com
65/79
grand texte Remarquez que j'ai utilis le mme indice pour cette notification et celle de la sous-partie prcdente. Cela permettra Android de rcuprer une notification (si elle est construite) plutt que d'en crer une nouvelle. C'est une bonne pratique lorsque vous concevez des applications Android. Tentez de la respecter le plus possible.
Grande image
La grande image est trs similaire la notification avec un grand texte, c'est pourquoi je vais vous laisser rflchir la faon de faire pour lancer ce type de notifications. Sachez simplement que vous allez devoir utiliser la classe
www.siteduzero.com
66/79
grande image
Correction
Sans surprise, je pense que vous tes arriv aisment au mme rsultat que moi : Code : Java Builder builder = new NotificationCompat.Builder(this);
www.siteduzero.com
67/79
www.siteduzero.com
68/79
liste
Correction
Code : Java Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle(getResources().getText(R.string.inbox_title)) .setSmallIcon(R.drawable.ic_launcher); InboxStyle inbox = new NotificationCompat.InboxStyle(builder); Notification notification = inbox.addLine("Line 1").addLine("Line 2") .setSummaryText("You have 2 messages").build();
www.siteduzero.com
69/79
www.siteduzero.com
70/79
www.siteduzero.com
71/79
www.siteduzero.com
72/79
Qu'avons-nous l ? Tout simplement un message qui comporte un tableau de record, d'enregistrement, avec un header (comportant des informations comme son identifiant et autres et un payload qui est la donne en elle-mme). Chaque record possde un espace mmoire assez rduit. Il faut donc penser les rpartir sur plusieurs records si nous implmentons une application qui crit des NDEF messages sur des tags ou bien rcuprer chaque record si nous implmentons un lecteur. Chose que nous allons faire dans la suite de ce chapitre.
Maintenant, pour les activits qui seront destines grer le NFC, nous devrons ajouter un noeud <intent-filter> avec un lment <action> qui indiquera le type de tag que nous traitons et la catgorie du filtre avec un lment <category>. Nous aurons donc quelque chose comme ceci : Code : XML <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
Avec ce filtre, le systme sera que nous traitons les tags NDEF et pourra proposer notre activit lorsqu'il captera un tag de ce type.
www.siteduzero.com
73/79
d'affichage pour afficher simplement un texte qui sera modifier par le texte que nous enverrons par un tag (ou par une mthode explique plus loin pour simuler un tag). Quant notre activit, nous nous contenterons de dsrialiser ce fichier XML et de jouer avec l'adaptateur NFC, NfcAdapter. Son initialisation se fait avec la mthode public static NfcAdapter getDefaultAdapter(Context context) qui est une mthode statique pouvant tre appel partir de la classe prcdemment cite. Ds que c'est chose faite, nous devons vrifier que l'appareil qui tente de lancer l'activit a bien le NFC ou s'il est bien activ. Pensez qu'il est toujours possible pour un utilisateur de tlcharger une application qui ne lui est pas destine initialement. Il pourrait donc installer une application qui ne figure pas sur son Play Store parce que ses appareils enregistrs ne sont pas compatibles. Nous vrifierons que notre adaptateur est bien diffrent de null ou s'il est bien activ par la mthode public boolean isEnabled(). Notre mthode public void onCreate(Bundle savedInstanceState) ressemblera donc quelque chose comme le code ci-dessous. Code : Java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_nfc); this.mTextView = (TextView) findViewById(R.id.textView1); this.mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { Toast.makeText(this, R.string.text_no_nfc, Toast.LENGTH_SHORT).show(); finish(); return; } }
Maintenant, pour que notre activit puisse grer la dcouverte d'un TAG au premier plan, il est ncessaire de redfinir la mthode protected void onResume() et la mthode protected void onPause(). Dans la premire mthode, nous activerons la possibilit d'identifier le tag pass dans un Intent via la mthode public void enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists). A quoi correspondent tous ces paramtres ? Le paramtre Activity est bien entendu destin renseigner l'activit sur lequel vous vous trouvez. Le paramtre PendingIntent renseigne un intent excuter plus tard pour indiquer l'activit qui se charge du traitement du tag. Le paramtre IntentFilter[] pour affiner le traitement des messages, mettre null si vous acceptez tout. Le paramtre String[][] est renseign pour excuter un matching de traitement avec le type de tag de priorit infrieur, mettre null si vous ne voulez rien matcher. Quant la seconde mthode, nous devons dsactiver cette possibilit de traitement des tags sur l'activit au premier plan par la mthode public void disableForegroundDispatch(Activity activity) en renseignant simplement l'activit courante. V ous aurez donc une implmentation similaire au code suivant : Code : Java @Override protected void onResume() { super.onResume(); Intent intent = new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0); IntentFilter[] filters = null; String[][] techListArray = null; mNfcAdapter.enableForegroundDispatch(this, pIntent, filters, techListArray); } @Override
www.siteduzero.com
74/79
Pour finir, nous allons voir comment traiter notre intent qui comporte notre NDEF message. Nous allons donc crer une mthode avec la signature private void resolveIntent(Intent intent) qui rcuprera un tableau de Parcelable correspondant aux donnes extensions placs par le tag, et ce via la mthode public Parcelable[] getParcelableArrayExtra(String name) en lui passant en paramtre la constante NfcAdapter.EXTRA_NDEF_MESSAGES. A partir de l, nous pourrons recopier son contenu dans un tableau du type NdefMessage et traiter les donnes comme bon nous semble. Si nous prenons un exemple simple o il existe simplement des donnes dans le premier enregistrement du message NDEF, on aura une mthode similaire : Code : Java private void resolveIntent(Intent intent) { String action = intent.getAction(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMsgs != null) { NdefMessage[] messages = new NdefMessage[rawMsgs.length]; for (int i = 0; i < rawMsgs.length; i++) { messages[i] = (NdefMessage) rawMsgs[i]; } // Exemple basique de rcupration des donnes dans le tableau String str = new String(messages[0].getRecords()[0].getPayload()); mTextView.setText(str); } } }
Il vous suffit alors d'appeler cette mthode la fin de la mthode public void onCreate(Bundle savedInstanceState) de votre activit pour grer l'intent que vous recevrez dans votre activit lorsque votre systme captera un tag NDEF. V otre application est maintenant capable d'intercepter les messages NDEF dcouvert par votre systme et proposera donc votre activit pour les lire.
www.siteduzero.com
75/79
Pour des soucis de facilit, j'ai plac ces mthodes en static dans une classe utilitaire NFCUtils.
Dans notre activit, nous utiliserons la mthode public static NdefMessage createMessage(String text, boolean encode) que nous appellerons lorsqu'un utilisera cliquera sur un bouton pour lancer un intent test comportant un message que nous avons dfini de la manire suivante : Code : Java public void sendTag(View v) { Intent i = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED); NdefMessage[] messages = new NdefMessage[1]; messages[0] = NFCUtils.createMessage("Simule message NDEF", true); i.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, messages); startActivity(i); }
Ainsi, lorsque nous cliquerons sur le bouton, notre systme nous proposera notre premire activit qui offre la possibilit de grer des NDEF messages.
www.siteduzero.com
76/79
NDEF
www.siteduzero.com
77/79
Commenons par implmenter une interface dans notre activit, CreateNdefMessageCallback. Comme vous pouvez le deviner, cette interface servira implmenter les mthodes pour crer les messages NDEF lorsque nous envoyons des donnes un autre terminal.Nous implmentons donc la mthode public NdefMessage createNdefMessage(NfcEvent event) de faon trs similaire notre mulateur, quelques exceptions prs. Nous aurons besoin de la mthode suivante pour crer un mime : Code : Java public static NdefRecord createMimeRecord(String mimeType, byte[] payload) { byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII")); NdefRecord mimeRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload); return mimeRecord; }
Le mime nous permettra d'indiquer le chemin vers le paquetage contenant l'activit qui permettra de traiter le transfert Beam. Nous devrons donc initialiser un tableau de record qui comporte l'enregistrement mime et le payload reprsentant la donne transfrer. Empaqueter le tout dans un NdefMessage pour ensuite le retourner dans la mthode. Nous obtenons donc simplement le code suivant : Code : Java @Override public NdefMessage createNdefMessage(NfcEvent event) { String text = "Message share by Beam !"; NdefRecord[] records = new NdefRecord[] { NFCUtils.createMimeRecord( "application/com.siteduzero.android.nfc", text.getBytes()) }; NdefMessage msg = new NdefMessage(records); return msg; }
Maintenant, pour rendre actif l'appel cette mthode, nous allons appeler, dans la mthode protected void onCreate(Bundle savedInstanceState), la mthode public void setNdefPushMessageCallback (NfcAdapter.CreateNdefMessageCallback callback, Activity activity, Activity... activities) sur l'adaptateur NFC que nous avons initialis juste avant. Nous lui donnons donc l'instance du callback en paramtre et l'activit courante dans laquelle il se trouve pour rendre oprationnel notre code. La rception des messages se fait exactement de la mme faon que prcdent sauf qu'il vous faudra redfinir une mthode supplmentaire public void onNewIntent(Intent intent) pour appeler la mthode private void resolveIntent(Intent intent) dveloppe dans la sous partie prcdente de ce chapitre. A partir de l, si vous excutez votre code et que vous mettez dos dos deux terminaux avec la technologie Beam, vous arrivez au resultat suivant :
www.siteduzero.com
78/79
Bien entendu, ce tutoriel est trs loin d'tre termin. V ous pourrez retrouver ce mme tutoriel en bta via ce lien. N'hsitez pas me donner votre avis pour faire voluer ce tutoriel. Il a pour but d'tre le plus communautaire possible. Je suis donc ouvert toutes vos critiques, questions et remarques constructives !
Remerciements
Aux lecteurs et bta-testeurs qui me font des critiques constructives sur le contenu de mon tutoriel. Fumble pour la validation de mon tutoriel. Bluekicks pour l'icne de mon tutoriel.
www.siteduzero.com