Je pense que nous serons tous d'accord pour dire qu'un Navigation Drawer qui n'affiche pas de page lorsqu'on clique sur un élément du menu... et bien ça ne sert à pas grand chose !
Dans ce chapitre, nous allons donc remédier à ce problème.
Nous poursuivrons le développement de notre mini-application MyNavDrawer, dont le code source est disponible à ce lien.
Création des pages
Nous allons reprendre l'exemple de notre précédente application développée lors du chapitre sur le ViewPager, MyAmazingViewPager.
En effet, nous allons créer 3 fragments correspondant aux pages que l'on souhaite afficher (NewsFragment, ProfileFragment et ParamsFragment).
Je vous crée le premier fragment et son layout, NewsFragment, et vous créerez ensuite vous-même les deux suivants (ProfileFragment et ParamsFragment) à l'identique (en changeant tout de même les noms des classes, attention... ).
Fichier NewsFragment.java :
public class NewsFragment extends Fragment {
public static NewsFragment newInstance() {
return (new NewsFragment());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_news, container, false);
}
}
Fichier fragment_news.xml :
android:id="@+id/fragment_news_rootview"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.openclassrooms.mynavdrawer.Controllers.Fragments.NewsFragment"
android:gravity="center"
android:background="#EDD9CF"
android:id="@+id/fragment_page_news_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dip"
android:textSize="25sp"
android:textStyle="bold"
android:textColor="#fff"
android:textAlignment="center"
android:text="Nous pourrions afficher un fil d'actualité ici non ?"
Une fois toutes nos pages (fragments) créées, il faut les afficher quand un utilisateur clique sur un élément du menu. Pour cela, nous allons utiliser notre copain, le FragmentManager.
Extrait du fichier MainActivity :
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
...
//FOR FRAGMENTS
// 1 - Declare fragment handled by Navigation Drawer
private Fragment fragmentNews;
private Fragment fragmentProfile;
private Fragment fragmentParams;
//FOR DATAS
// 2 - Identify each fragment with a number
private static final int FRAGMENT_NEWS = 0;
private static final int FRAGMENT_PROFILE = 1;
private static final int FRAGMENT_PARAMS = 2;
...
@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
// 6 - Show fragment after user clicked on a menu item
switch (id){
case R.id.activity_main_drawer_news :
this.showFragment(FRAGMENT_NEWS);
break;
case R.id.activity_main_drawer_profile:
this.showFragment(FRAGMENT_PROFILE);
break;
case R.id.activity_main_drawer_settings:
this.showFragment(FRAGMENT_PARAMS);
break;
default:
break;
}
this.drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
...
// ---------------------
// FRAGMENTS
// ---------------------
// 5 - Show fragment according an Identifier
private void showFragment(int fragmentIdentifier){
switch (fragmentIdentifier){
case FRAGMENT_NEWS :
this.showNewsFragment();
break;
case FRAGMENT_PROFILE:
this.showProfileFragment();
break;
case FRAGMENT_PARAMS:
this.showParamsFragment();
break;
default:
break;
}
}
// ---
// 4 - Create each fragment page and show it
private void showNewsFragment(){
if (this.fragmentNews == null) this.fragmentNews = NewsFragment.newInstance();
this.startTransactionFragment(this.fragmentNews);
}
private void showParamsFragment(){
if (this.fragmentParams == null) this.fragmentParams = ParamsFragment.newInstance();
this.startTransactionFragment(this.fragmentParams);
}
private void showProfileFragment(){
if (this.fragmentProfile == null) this.fragmentProfile = ProfileFragment.newInstance();
this.startTransactionFragment(this.fragmentProfile);
}
// ---
// 3 - Generic method that will replace and show a fragment inside the MainActivity Frame Layout
private void startTransactionFragment(Fragment fragment){
if (!fragment.isVisible()){
getSupportFragmentManager().beginTransaction()
.replace(R.id.activity_main_frame_layout, fragment).commit();
}
}
Explications : Dans MainActivity, nous allons faire en sorte d'afficher un à un nos fragments (au sein du FrameLayout déjà défini), dès lors qu'un utilisateur appuiera sur un élément du menu :
Ligne 1 : Dans un premier temps, nous allons déclarer en haut de notre classe les différents fragments (pages) que nous allons utiliser.
Ligne 2 : Nous allons maintenant identifier nos fragments grâce à des numéros uniques. Vous allez comprendre pourquoi très vite...
Ligne 3 : Cette méthode générique,
startTransactionFragment(Fragment fragment)
, sera appelée à chaque fois que nous souhaiterons que le FragmentManager affiche un de nos trois fragments dans le FrameLayout.Ligne 4 : Pour chacun de nos fragments, nous développons une méthode qui permettra de les instancier pour ensuite les afficher.
Ligne 5 : Cette dernière méthode,
showFragment(int fragmentIdentifier)
, elle aussi assez générique, nous permettra en fonction de l'identifiant passé en paramètre (d'où l'intérêt d'avoir créé nos identifiants dans la ligne 2) d'afficher le bon fragment.Nous nous servirons dorénavant uniquement de cette méthode pour afficher nos différents fragments au sein de l'activité.
Ligne 6 : Enfin, nous mettons à jour la méthode
onNavigationItemSelected( )
, appelée à chaque fois qu'un utilisateur clique sur un élément du menu, afin d'afficher le fragment correspondant.
Lancez maintenant votre application. Le résultat est plutôt satisfaisant non ?
Cependant, minutieux et perfectionniste comme vous êtes, vous relevez un point problématique : au lancement de l'application, aucun fragment n'est lancé par défaut. Du coup, un écran blanc apparaît... Que faire ?
Je vous laisse y réfléchir quelques minutes. N'hésitez également pas à tester différents bouts de code afin de résoudre ce mini-problème ! Habituez-vous y dès maintenant, résoudre des problèmes deviendra votre tâche numéro 1 lorsque vous serez développeur !
Je vous donne entre-temps ma solution...
Extrait du fichier MainActivity.java :
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
// 2 - Show First Fragment
this.showFirstFragment();
}
...
// ---------------------
// FRAGMENTS
// ---------------------
// 1 - Show first fragment when activity is created
private void showFirstFragment(){
Fragment visibleFragment = getSupportFragmentManager().findFragmentById(R.id.activity_main_frame_layout);
if (visibleFragment == null){
// 1.1 - Show News Fragment
this.showFragment(FRAGMENT_NEWS);
// 1.2 - Mark as selected the menu item corresponding to NewsFragment
this.navigationView.getMenu().getItem(0).setChecked(true);
}
}
...
}
Explications : Afin d'afficher notre premier fragment à la création de notre activité, nous devons vérifier si le conteneur de fragment (FrameLayout) est vide.
Ligne 1 : Pour cela, nous allons créer une méthode,
showFirstFragment()
, qui tentera de récupérer le fragment affiché dans le conteneur de fragment FrameLayout. Si aucun fragment n'est affiché, alors nous afficherons (1.1) le fragment NewsFragment.Nous indiquerons ensuite (1.2) l'élément du menu correspondant, comme "sélectionné" (en l'occurence ici, le premier).
Ligne 2 : La méthode
showFirstFragment()
sera appelée à la création de l'activity MainActivity, donc dans leonCreate()
.
Et voilà ! Vous avez maintenant un NavigationDrawer complètement fonctionnel. N'hésitez pas à le faire évoluer en fonction de vos envies et de vos besoins, c'est comme cela que vous progresserez !
Conclusion
Avec ces deux derniers chapitres, nous avons vu ensemble le fonctionnement et l'implémentation d'un NavigationDrawer. Chouette !
Ce dernier, certes un peu long à développer, vous permettra de créer un système de navigation au sein de votre application complet et efficace, largement plébiscité dans le monde Android.
Vous trouverez l'application MyNavDrawer terminée à ce lien.