Attention, le contenu cet article est peut-être obsolète !
Comment créer une menu utilisant des fragments avec AndroidDevenu à la mode, le système de navigation par menu utilisant des fragments, appelé drawer, est une alternative intéressante à un menu classique lançant des activités. Ici, nous n'avons qu'une activité.
Je vous invite à regarder la doc' officielle pour que vous compreniez la différence entre un fragment et une activité. Nous allons voir ici comment créer un menu avec fragment.
Imaginons que vous vouliez un menu comptant 4 éléments :
C'est parti !
Tout d'abord, créez votre fichier strings.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Mon application</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Paramètres</string>
<!-- Menu drawer -->
<string name="drawer_open">Menu ouvert</string>
<string name="drawer_close">Menu fermé</string>
<!-- Elements du menu -->
<string-array name="nav_drawer_items">
<item>Accueil</item>
<item>Simulation</item>
<item>On vous rappelle</item>
<item>Contact</item>
</string-array>
<!-- Icones du menu, pour des raisons de simplicité dans l'exemple je utilise la même icone partout -->
<array name="nav_drawer_icons">
<item>@drawable/menu_home</item>
<item>@drawable/menu_home</item>
<item>@drawable/menu_home</item>
<item>@drawable/menu_home</item>
</array>
</resources>
Créons à présent la vue de l'activité : activity_main.xml dans layout
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Frame qui contiendra les fragments -->
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Listviw qui contiendra les éléments du menu-->
<ListView
android:id="@+id/list_slidermenu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#FFFFFF"
android:dividerHeight="1dp"
android:listSelector="#4849B4"
android:background="#87398F"/>
</android.support.v4.widget.DrawerLayout>
Créez à présent un dossier drawable dans res et placez-y ces fichiers :
list_item_bg_normal.xml :
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#00529B"
android:endColor="#09A3E2"
android:angle="90" />
</shape>
list_item_bg_pressed.xml :
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#19478A"
android:endColor="#1B91C3"
android:angle="90" />
</shape>
list_selector.xml :
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/list_item_bg_normal" android:state_activated="false"/>
<item android:drawable="@drawable/list_item_bg_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/list_item_bg_pressed" android:state_activated="true"/>
</selector>
counter_bg.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#DC572E" >
</solid>
<padding
android:right="3dp"
android:left="3dp" >
</padding>
<corners android:radius="2dp" >
</corners>
</shape>
Retournez dans le dossier layout, pour créer un fichier drawer_list_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/list_selector">
<ImageView
android:id="@+id/icon"
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:contentDescription="@string/desc_list_item_icon"
android:src="@drawable/ic_launcher"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@id/icon"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textColor="#FFFFFF"
android:gravity="center_vertical"
android:paddingRight="40dp"/>
<TextView android:id="@+id/counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/counter_bg"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="8dp"
android:textColor="#000000"/>
</RelativeLayout>
Maintenant passons au code.
NavDrawerItem.java :
public class NavDrawerItem {
private String title;
private int icon;
private String count = "0";
private boolean isCounterVisible = false;
public NavDrawerItem(){}
public NavDrawerItem(String title, int icon){
this.title = title;
this.icon = icon;
}
public NavDrawerItem(String title, int icon, boolean isCounterVisible, String count){
this.title = title;
this.icon = icon;
this.isCounterVisible = isCounterVisible;
this.count = count;
}
public String getTitle(){
return this.title;
}
public int getIcon(){
return this.icon;
}
public String getCount(){
return this.count;
}
public boolean getCounterVisibility(){
return this.isCounterVisible;
}
public void setTitle(String title){
this.title = title;
}
public void setIcon(int icon){
this.icon = icon;
}
public void setCount(String count){
this.count = count;
}
public void setCounterVisibility(boolean isCounterVisible){
this.isCounterVisible = isCounterVisible;
}
}
NavDrawerListAdapter.java :
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class NavDrawerListAdapter extends BaseAdapter {
private Context context;
private ArrayList<NavDrawerItem> navDrawerItems;
public NavDrawerListAdapter(Context context, ArrayList<NavDrawerItem> navDrawerItems){
this.context = context;
this.navDrawerItems = navDrawerItems;
}
@Override
public int getCount() {
return navDrawerItems.size();
}
@Override
public Object getItem(int position) {
return navDrawerItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.drawer_list_item, null);
}
ImageView imgIcon = (ImageView) convertView.findViewById(R.id.icon);
TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
TextView txtCount = (TextView) convertView.findViewById(R.id.counter);
imgIcon.setImageResource(navDrawerItems.get(position).getIcon());
txtTitle.setText(navDrawerItems.get(position).getTitle());
if(navDrawerItems.get(position).getCounterVisibility()){
txtCount.setText(navDrawerItems.get(position).getCount());
}else{
txtCount.setVisibility(View.GONE);
}
return convertView;
}
}
Il est temps de s'occuper de l'activité principale : MainActivity.java :
public class MainActivity extends Activity implements TaskCallbacks{
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
// Titre du menu
private CharSequence mDrawerTitle;
// Titre de l'application
private CharSequence mTitle;
// Elements du menu
private String[] navMenuTitles;
private TypedArray navMenuIcons;
private ArrayList<NavDrawerItem> navDrawerItems;
private NavDrawerListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
// Chargement des éléments du menu
navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
// Chargement des icones du menu
navMenuIcons = getResources()
.obtainTypedArray(R.array.nav_drawer_icons);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
navDrawerItems = new ArrayList<NavDrawerItem>();
/* Ajout des éléments du menu dans le tablea*/
// Home
navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons
.getResourceId(0, -1)));
// Simulation
navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons
.getResourceId(1, -1)));
// Rappel Auto
navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], navMenuIcons
.getResourceId(2, -1)));
// Contact
//navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons.getResourceId(3, -1), true, "22"));
navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons
.getResourceId(3, -1)));
/* *************************************************** */
// Vidons la mémoire prise par des éléments déja chargé, en l'occurence
// les icones
navMenuIcons.recycle();
mDrawerList.setOnItemClickListener(new SlideMenuClickListener());
// mise en place de l'adapter pour le menu
adapter = new NavDrawerListAdapter(getApplicationContext(),
navDrawerItems);
mDrawerList.setAdapter(adapter);
// Activation de l'action bar
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.menu_icon, // Icone du menu
R.string.app_name, // nav drawer ouvert
R.string.app_name // nav drawer fermé
) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
// Affiche les premiers éléments du menu lors de la première
// utilisation de l'appli
displayView(0);
}
} /* *************** FIN OnCreate() ********************************** */
/* Ecoute clic sur élément du menu */
private class SlideMenuClickListener implements
ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// affiche la vue de l'élément sélectionné. C'est ici que l'on définira le comportement de l'appli
displayView(position);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
//Déploie le menu quand on clic sur l'icone du menu
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Gestion des clics sur la action bar
switch (item.getItemId()) {
case R.id.action_settings:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/* *** dans le cas où invalidateOptionsMenu() est appelé *** */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Si le menu est déployé on cache le menu options
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
/* Gestion des fragments, méthode appelé par l'écouteur de clic sur le menu */
private void displayView(int position) {
// Mise à jour du fragment principal, remplacé par le nouveau
Fragment fragment = null;
switch (position) {
case 0: //Accueil
fragment = new HomeFragment();
break;
case 1: // Simulation
//fragment = new DevisFragment();
break;
case 2: // Rappel auto
//fragment = new RappelAutoFragment();
break;
case 3: // Email
//fragment = new EmailFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// Mise à jour du titre, du menu (selected item) et ferme le menu
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
Log.e("MainActivity", "Erreur dans la création du fragment");
}
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
/* Les méthodes ci-dessous sont appelées dans le cas de l'utilisation d'un élément de l'options menu */
/* Par exemple pour re-synchroniser la configuration de l'application */
/* Mais ici on n'aura pas à s'en servir étant donné les fonctions de notre application */
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
Enfin créons un fragment, le premier. Les autres sont mis en commentaires dans le code ci-dessus, je vous laisse créer les vôtres.
Donc pour notre premier fragment, la vue :
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txtLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="16dp"
android:text="Home View"/>
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/txtLabel"
android:src="@drawable/ic_launcher"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"/>
</RelativeLayout>
HomeFragment.java :
public class HomeFragment extends Fragment {
public HomeFragment(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
return rootView;
}
}
Et voilà !