Dynamic-Mess.com


"The world is a dynamic mess of jiggling things..."

Android : créer un menu avec fragments

Article posté le 05-08-2014 dans la catégorie Android

Attention, le contenu cet article est peut-être obsolète!

Devenu à 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 !

1- Apparence

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>

 

2- Le code

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à !


Cet article vous a plu? Découvrez d'autres articles


Tweet
comments powered by Disqus