Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Dans l'article introductif aux menus on a mentionné l'existence des 3 types des menus. Ici on présentera le premier type qui est le menu d'options.

Implémenter menu d'options sous Android

Le menu d'options dans notre application sera composé d'un seul élément : l'action qui permettra de changer la langue. Le menu d'options sera placé dans la partie des ressources (/res/menu) sous le nom menu.xml. Voici le fichier :

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
        android:id="@+id/lang_change"
	    android:orderInCategory="100"
	    android:showAsAction="never"
	    android:actionViewClass="android.widget.Spinner"
	    android:title="@string/lang_change"/>

</menu>

Certains nouveaux attributs ont apparu à cette occasion :
- android:orderInCategory : spécifie la position à laquelle doit s'afficher l'élément du menu. Dans notre cas il n'est pas utile, mais il est important de connaître son existance.
- android:showAsAction : détermine si l'élément peut s'afficher dans Action Bar (consultez l'article Action Bar sous Android pour en savoir plus). Dans notre cas, on ne veut pas l'y afficher.
- android:actionViewClass : indique le nom de la classe qui sera utilisée pour rendre l'élément de menu visible. En occurrence, on utilisera la liste déroulante. La configuration de cette classe peut être fait dans la méthode de création du menu d'option (onCreateOptionsMenu()). Il suffit juste de la récupérer (menu.findItem(R.id.lang_change).getActionView() pour le configurer et soumettre dans la méthode du parent (super.onCreateOptionsMenu(menu)).

Regardons maintenant la méthode qui s'occupe de charger le menu et une autre pour gérer la sélection de l'élément du menu par l'utilisateur :

public class BaseActivity extends FragmentActivity {
    // ...
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        boolean result = false;
        if (menuItem.getItemId() == R.id.lang_change) {
            result = true;
            Log.d(LOG_TAG, "Clicked on menu item lang_change");

            Resources resources = getResources();
            locales = resources.getStringArray(R.array.langs);
            if (locales == null || locales.length == 0) {
                showErrorBox(resources.getString(R.string.no_langs_title), resources.getString(R.string.no_langs_msg), 
                resources.getString(R.string.dialog_error_refresh), resources.getString(R.string.dialog_error_quit));
            } else {
                LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                final View langModifierView = inflater.inflate(R.layout.switch_lang, (ViewGroup) null, true);
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
                // set title
                alertDialogBuilder.setTitle(resources.getString(R.string.lang_choose));

                // set view with form data 
                eealertDialogBuilder.setView(langModifierView);
    
                final Context globalContext = this;
                final Spinner type = (Spinner) langModifierView.findViewById(R.id.newLangSwitched);
                type.setOnItemSelectedListener(new OnItemSelectedListener() {
                    @Override
                    public void onItemSelected(AdapterView parentView, View selectedItemView, int position, long id) {
                        Log.d(LOG_TAG, "Found spinner"+type);
                        newLangName = type.getSelectedItem().toString();
                        langPosition = position;
                        Log.d(LOG_TAG, "Selected item position is " + position);
                        Log.d(LOG_TAG, "Found lang name" + newLangName);
                    }
                    @Override
                    public void onNothingSelected(AdapterView parentView) {}
                });

                // set dialog message
                alertDialogBuilder
                .setMessage(resources.getString(R.string.lang_select))
                .setCancelable(true)
                .setPositiveButton(resources.getString(R.string.form_submit),new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int id) {    
                        dialog.cancel();
                        Locale locale = new Locale(locales[langPosition]);
                        Locale.setDefault(locale);
                        Configuration config = new Configuration();
                        config.locale = locale;
                        globalContext.getResources().updateConfiguration(config, globalContext.getResources().getDisplayMetrics());
                        refreshActivity();
                    }
                })
                .setNegativeButton(resources.getString(R.string.form_cancel),new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int id) {
                        dialog.cancel();
                    }
                });
                // create alert dialog
                AlertDialog alertDialog = alertDialogBuilder.create();
                // show it
                alertDialog.show();
            }
        }
        return result;
    }
}

La création du menu se fait dans onCreateOptionsMenu() par l'appel du layout et son passage à la même méthode du parent. La fonction onOptionsItemSelected() est plus intéressante. Tout d'abord on vérifie quel élément a été sélectionné. S'il s'agit de celui qui sert à changer la langue, on déclenche les actions qui consistent à :
- créer le layout avec le Spinner
- associer des écouteurs à des boutons
- afficher le dialog

Partie de traitement des dialogs a été expliquée dans l'article consacrée au dialog sous Android.

Bartosz KONIECZNY Menus

Une question ? Une remarque ?

*

*

Un conseil Symfony2

Comment utiliser les routes d'un autre environnement ?

En utilisant les routes d'un autre environnement sous Symfony2 on risque de voir le nom du dispatcher. Supossons qu'on est placé dans notre backoffice, déclenché avec le fichier administration.php . On se trouve donc dans un url /administration.php/admin/get/order/1 . L'environnement courant est donc "administration". Si l'on veut appeler une route de l'environnement "frontend", "/show/order/1", on risque de voir l'url suivant : /administration.php/show/order/1 . Cela est provoqué par le fait que Symfony2 reprend l'environnement actuel. Pour éviter ce genre de situations, il faut récupérer l'objet qui gère la génération des urls pour l'environnement donné. Ensuite, temporairement, il faut lui indiquer l'url de base à utiliser pour les chemins. Voici le code qui devrait résoudre ce problème :

$generator = $this->container->get('router')->getGenerator();
// var_dump($generator->getOption('baseurl'));
// Symfony\Component\Routing\RequestContext
$requestContext = $generator->getContext();
// sets base URL used in the generated URL
$requestContext->setBaseUrl('frontend.php');
// var_dump($requestContext);
$generator->setContext($requestContext);
//var_dump($generator);
echo $this->generateUrl('showOrder', array('id' => 1));
// will show /frontend.php/show/order/1 url