«

»

ene 03 2013

Introducción a SlidingMenu (menú lateral)

 

Android ha cambiado mucho desde sus inicios hasta ahora, diferentes patrones de diseño han ido emergiendo a lo largo de su historia para hacer más conveniente el uso de pantallas táctiles. Ya no sirven convenciones como las que existían en los teléfonos de botones o en las ya obsoletas PDAs.

Las pantallas que se pueden tocar con los dedos requieren otros mecanismos para poder interactuar con ellas de forma cómoda. Al principio Google propuso el patrón dashboard para navegar entre diferentes partes independientes de la aplicación, partes que se pudieran considerar tareas distintas dentro de la misma actividad, de modo que el usuario pulsaba un botón “inicio” para volver al dashboard de la aplicación y desde allí acceder a otra parte de la misma. Pongamos por ejemplo la aplicación antigua de twitter, se presentaba un dashboard desde el que podías navegar entre tu timeline, menciones, mensajes directos, listas, etc.

 

Dashboard del antiguo twitter

 

Con la llegada de Honeycomb, este patrón quedó obsoleto a favor de un menú desplegable en la action bar para poder navegar entre distintas tareas de una misma aplicación sin pasar por una pantalla intermedia. Pero este patrón no ha llegado a calar muy hondo porque, por lo menos a mi, me resulta extraño, y no está claro si es para cambiar el modo de visualización, cambiar de tarea, etc.

Es por eso que recientemente se ha empezado a adoptar el patrón del menú lateral. Empezó siendo la aplicación de Facebook la que lo introdujo por primera vez de forma masiva (¡ni siquiera era una aplicación nativa!) y poco a poco se fue popularizando. Ahora lo vemos en la app de Google+, Evernote, Spotify y muchas otras, por la flexibilidad que ofrece. No solo nos vale para mostrar una lista de cosas que podemos hacer con la aplicación, sino que muchas veces integra otras opciones como los favoritos, buscador, accesos directos en forma de rejilla, y prácticamente lo que queramos incluir ya que es un layout como otro cualquiera. Al final Google ha decidido integrarlo como un patrón de interfaz más en su guía de estilo aunque no ofrece ningún componente (aún) para implementarlo.

Cyril Mottier lo integró magistralmente en su aplicación Prixing y en su blog nos explica cómo lo hizo a un nivel teórico, y ha sido Jeremy Feinstein el que ha creado la librería de menú lateral más usada y es la que os voy a explicar aquí.

 

Lo primero es descargarnos la librería SlidingMenu de github (es una gozada tener todas estas estupendas librerías completamente libres) .

Enlazamos la librería a nuestro proyecto en las propiedades del proyecto > android > Add library.

Luego, tenemos tres formas de añadir un menú lateral, una es heredando de la clase SlidingActivity de la librería en vez de la clase Activity u otra, de esta manera tendremos los métodos del menú integrados en la actividad. Si usamos ActionBarSherlock no podremos cambiar la actividad de la que heredamos, pero podemos irnos a la clase SlidingActivity (o SlidingFragmentActivity si usamos fragments) de la librería y hacer que herede de SherlockActivity (o de SherlockFragmentActivity). Para esto tendremos que enlazar tambien la librería ActionBarSherlock a la librería SlidingMenu.

Otra forma de integrar un menú lateral es via layout, añadiendo a nuestro layout una view y configurar los atributos de nuestro menú y añadir ahí las vistas que queramos en nuestro menú lateral. Este método ofrece algunas posibilidades extra como por ejemplo, añadir un menú lateral a una fila de una lista (¡esto debe molar mucho!). Además de esta forma podemos indicar en los archivos de recursos algunas dimensiones dependiendo de la orientación de la pantalla o la densidad de esta. Éstas dimensiones pueden ser el margen que queda visible, tamaño de la sombra, etc. Un ejemplo sería:

 

<com.slidingmenu.lib.SlidingMenu
    xmlns:sliding="http://schemas.android.com/apk/res-auto"
    android:id="@+id/slidingmenulayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    sliding:viewAbove="@layout/YOUR_ABOVE_VIEW"
    sliding:viewBehind="@layout/YOUR_BEHIND_BEHIND"
    sliding:touchModeAbove="margin|fullscreen"
    sliding:behindOffset="@dimen/YOUR_OFFSET"
    sliding:behindWidth="@dimen/YOUR_WIDTH"
    sliding:behindScrollScale="@dimen/YOUR_SCALE"
    sliding:shadowDrawable="@drawable/YOUR_SHADOW"
    sliding:shadowWidth="@dimen/YOUR_SHADOW_WIDTH"
    sliding:fadeEnabled="true|false"
    sliding:fadeDegree="float"
    sliding:selectorEnabled="true|false"
    sliding:selectorDrawable="@drawable/YOUR_SELECTOR"/>

 

La tercera forma es crear el menú desde código instanciándolo con el constructor, inicializar todas las propiedades de presentación y añadirlo a la activity, de forma que lo podemos incorporar dinámicamente a cualquier actividad o incluso añadir distintos menús en función de otros parámetros (por ejemplo si el usuario está logueado o no).

Además la propia librería nos permite decidir si queremos desplazar la ActionBar al abrir el menú o solo el contenido debajo de ésta, para eso podemos indicar en el parámetro flag del método attachToActivity como SlidingMenu.SLIDING_WINDOW si queremos deslizar todo o SlidingMenu.SLIDING_CONTENT si queremos sólo el contenido.

Por ejemplo:

 

public class SlidingExample extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.attach);
        // set the content view
        setContentView(R.layout.content);
        // configure the SlidingMenu
        SlidingMenu menu = new SlidingMenu(this);
        menu.setMode(SlidingMenu.LEFT);
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        menu.setShadowWidthRes(R.dimen.shadow_width);
        menu.setShadowDrawable(R.drawable.shadow);
        menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        menu.setFadeDegree(0.35f);
        menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
        menu.setMenu(R.layout.menu);
    }
}

 

Para saber qué son todas las propiedades lo mejor es irse a la página de la documentación.

Otra ventaja que tenemos es que podemos cargar un fragment en el menú lateral, por ejemplo un ListFragment, para esto podemos declararlo en el layout de la vista que está detrás de la pantalla principal o incluso declarar sólo un FrameLayout y añadir dentro el fragment dinámicamente o sustituirlo por el fragment una vez instanciado mediante el FragmentManager, por ejemplo:

 

//Set the front and behind content views
setContentView(R.layout.activity_main);
setBehindContentView(R.layout.behind_list_layout);
        
//Create the shop list fragment and replace the framelayout set in the behind view
mMyListFragment = new MyListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.framestub, mMyListFragment).commit();

 

Warning!

Si necesitamos tener la librería de soporte de android en varios proyectos (por ejemplo en ActionBarSherlock, en SlidingMenu y en nuestra app, recordad que debéis tener el mismo android-support-v4.jar u os dará un error por ser versiones diferentes).

 

Si queréis ver un ejemplo en funcionamiento, podéis descargar la aplicación de ejemplo desde Google Play

 

Ejemplo

 

¡Así de fácil! Espero que os haya gustado.

Acerca del autor

Fernando F. Gallego

Desarrollador de junaio Augmented Reality para Android desde Munich. Me encanta cacharrear y probar ideas y conceptos nuevos para aprender. Tengo tantos pet projects que podría montar un zoo de aplicaciones. Además me encanta el sushi, los gintonics y los smartphones. Puedes encontrarme en twitter como @ferdy182

  • http://alberto-alonso.com/ Alberto Alonso

    Yo no es que sea un experto, pero hacer un menu lateral es tan simple como ponerlo como oculto y mostrarlo cuando le das a algún botón, no necesitas ninguna libreria para hacer eso… o tan equivocado estoy?

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Pues depende de lo complejo y flexible que lo quieras hacer. Por supuesto puedes tener una vista que muestras u ocultas con un botón, pero la librería te permite muchas otras cosas, como por ejemplo, hacer que la actividad principal se deslice fuera de la pantalla dejando ver el menú como si estuviera debajo de la actividad, permite animación, permite aplicar una sombra u otras transformaciones mientras se muestra el menú, etc.

      La librería permite tener una implementación de una manera rápida y fácil sin tener que hacer todo tu.

  • Petru Rares

    Cuando entré tenia unas ganas increíbles de ver como funcionaba, pero al acabar al artículo me he decepcionado. Ya que no explica otra cosa que no se dice en el github del autor, menos la última pate. Podríais habéroslo currado un poco, como por ejemplo crear vuestra aplicación de ejemplo, pero más sencilla, explicar un poco Responsive Design, etc.

    • Jesús

      Si quieres ver a bastante bajo nivel como se puede realizar la implementación del menú lateral sería interesante que eches un ojo a este artículo: http://android.cyrilmottier.com/?p=717 . La verdad es que el artículo no está demasiado currado (en el readme de github de la librería se puede ver casi lo mismo aquí expuesto). Hubiera sido interesante que se hubiera explicado como aprovechar el resto de propiedades de la librería. Aunque como todo, es solo una opinión personal.

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Buenas,

      en el artículo se enlaza al blog de Cyril Mottier donde se explica a bajo nivel, de todos modos la librería no da mucho más de si, si quieres ver cómo funciona en un ejemplo, puedes instalar el ejemplo de Google Play https://play.google.com/store/apps/details?id=com.slidingmenu.example y ver lo que puedes hacer con ella. Es muy sencilla de usar y he explicado las tres maneras de usarla. Sobre el response design, puedes cambiar los valores en el archivo de dimens.xml para cada tamaño de pantalla, no tiene mucho más.

  • http://www.linkedin.com/in/jmpergar JMPergar

    Pensad que no todo los lectores de AndroCode tienen el mismo nivel y conocimientos de la plataforma y el ingles. Algunos si agradecen este tipos de post y les son de utilidad aunque no se profundice mas como algunos querrían.

  • http://www.aripagua.com Darry Castro

    Excelente esta este código, espero utilizarlo en un nuevo proyecto que tengo voy a ver que tal me va y le comento por esta vía.

    Gracias de antemano.
    Darry Castro

  • Robert

    Buenísimo de gran ayuda y utilidad ,aplicable para mi nueva aplicación en android.

    Gracias por este buen trabajo

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Gracias! me alegro de que te haya gustado.

  • Andres

    Estoy trabajando con el mismo menu , pero necesito invocar Actividades. tienes algo similar con fragment llamando a Activitys ? saludos..

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Si el contenido de tu menú lateral es un fragment, crea una interface en ese fragment para manejar la interación, por ejemplo, una interfaz que maneje un click en un elemento de la lista:

      public interface OnWebsiteSelectedListener {
      public void onWebsiteSelected(int position);
      }

      Crea una variable para almacenar la referencia:

      OnWebsiteSelectedListener mWebsiteListener;

      Luego tu actividad principal, digamos MainActivity, que contiene los fragments, haces que implemente esa interfaz:

      public class MainActivity extends SlidingFragmentActivity implements WebsiteList.OnWebsiteSelectedListener

      De vuelta al fragment, en onAttach, asignas la actividad a la variable que has creado antes:

      public void onAttach(Activity activity) {
      super.onAttach(activity);

      try {
      mWebsiteListener = (OnWebsiteSelectedListener) getActivity();
      } catch (ClassCastException e) {
      throw new ClassCastException(activity.toString() + ” must implement OnWebsiteSelectedListener”);
      }
      }

      Y ahora cuando hagas click en un elemento dentro del fragment, llamas al listener:

      @Override
      public void onListItemClick(ListView l, View v, int position, long id) {
      mWebsiteListener.onWebsiteSelected(position);
      }

      y como en la actividad principal has tenido que implementar esa interfaz, recibirá los datos que le pases, por ejemplo, la activity que quieras abrir, o reemplazar el fragment de tu actividad principal o lo que quieras hacer.

      @Override
      public void onWebsiteSelected(int position) {
      startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(“http://androcode.es”)));
      getSlidingMenu().toggle();
      }

      (Esto casi se merece otro artículo)

  • Andres

    Desde las opciones del menú yo intento llamar a una activity con intent pero el problema es que la transición que realiza es muy notoria ya que el activity aparece por encima y no con la transición que deberia hacia el lado.

    @Override
    public void onSideNavigationItemClick(int itemId) {
    // TODO Auto-generated method stub
    switch (itemId) {
    case R.id.side_navigation_menu_item1:
    Intent suscripcion = new Intent().setClass(EquiposActivity.this, SuscripcionActivity.class);
    startActivity(suscripcion);
    break;

    case R.id.side_navigation_menu_item2:
    Intent videos = new Intent().setClass(EquiposActivity.this, VideosActivity.class);
    startActivity(videos);
    break;

    default:
    return;
    }
    finish();

    Este es el metodo antiguo que el ejemplo usaba, pero este no invoca a una activity si no a una imagen.y eso es lo que yo no necesito.

    @Override
    public void onSideNavigationItemClick(int itemId) {
    switch (itemId) {
    case R.id.side_navigation_menu_item1:
    invokeActivity(getString(R.string.title1), R.drawable.ic_android1);
    break;
    }

    /**
    * Start activity from SideNavigation.
    *
    * @param title title of Activity
    * @param resId resource if of background image

    private void invokeActivity(String title, int resId) {
    Intent intent = new Intent(this, EquiposActivity.class);
    intent.putExtra(EXTRA_TITLE, title);
    intent.putExtra(EXTRA_RESOURCE_ID, resId);

    // all of the other activities on top of it will be closed and this
    // Intent will be delivered to the (now on top) old activity as a
    // new Intent.
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    startActivity(intent);
    // no animation of transition
    overridePendingTransition(0, 0);
    }

    Soy nuevo en esto , agradeceria tu ayuda
    saludos

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Si lo que quieres es que cambie el contenido de la actividad principal sin que salte a otra, tendrás que sustituir el fragment de la actividad principal por el nuevo que quieres cargar, y a la vez cerrar el menú.

      Si lanzas otra activity entonces te cargará todo nuevo y tendrías que implementar el menu lateral otra vez

  • chucherm

    Gracias por la información, cuando agrego la libreria a eclipse me marca un error en la clase SlidingMapActivity sobre MapActivity y con la librería de import com.google.android.maps.MapActivity;

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Asegúrate de que estás usando las Google APIs en vez del sdk de android a pelo.

  • javi

    Desde el punto de vista teórico está muy bien el artículo.

  • http://gravatar.com/ducapix ducatrx

    hola, genial el manual. Tengo una pregunta, no consigo cambiar, no el icono en si sino la flechita al lado del icono.Incluso me gustaría quitarlo todo y cambiarlo por las tipicas 3 lineas. Muchas gracias. ;-)

    • http://twitter.com/ferdy182 Fernando F. Gallego (@ferdy182)

      Hola, tienes que definirlo en tu propio theme, defines el drawable que quieras para el atributo android:homeAsUpIndicator

      @drawable/custom_home

      y homeAsUpIndicator para el ActionBarSherlock

      @drawable/custom_home

  • http://gravatar.com/javilque javilque

    Buenas, tutorial excelente.Tengo un problema con el sliding menu.he creado un menu con Textview y listview pero no sucede nada cuando selecciono un item del listview. y el menu tampoco cierra.
    Alguien podria ayudarme?No encuentro información sobre ello.

    @Override

    public boolean onOptionsItemSelected(MenuItem item) {

    if (item.getItemId() == R.id.lista_menu) {
    startActivity(new Intent(this, MostrarNotas.class));
    }

    Gracias

    • http://twitter.com/ferdy182 Fernando F. Gallego (@ferdy182)

      Hola, el listener onOptionsItemSelected es sólo para los menús que se sacan con los 3 puntitos o el botón de menú del teléfono. Para interactuar con las views que pongas en el menú lateral se hace como si fuera una vista normal en la pantalla principal, normalmente con onClick.

  • agreseagal

    Hola Fernando,

    Encuentro genial tu explicación así como tu app que recopila todas las posibilitdades. ¿Tienes colgado el código fuente en GitHub? Gracias!

    • https://www.facebook.com/fernando.f.gallego Fernando F. Gallego

      Hola, la app no es mía, y el código está enlazado desde el artículo. Saludos.

      • agreseagal

        Hola,

        he probado de compilarlo pero da errores por todos lados. He probado hacer clean y luego build habiendo enlazado la libreria pero nada. Está tal cual lo he descargado de GitHub. Alguna idea de que puede ser? En el README.md no dice nada más :(

        Gracias!

        • https://www.facebook.com/fernando.f.gallego Fernando F. Gallego

          Mira a ver que tengas seleccionada la versión del SDK de android que tengas descargada, sino elige una que tengas, en las propiedades del proyecto, también que tengas la misma versión de la librería de compatibilidad si la estás usando, en la consola suele poner cual es el problema

  • http://gravatar.com/zantiago12 zantiago12

    Hola, muy genial la libreria, pero soy nuevo eprogramando en Android y aun no se como importar esta libreria, ya que descargo el zip pero no se cual es ni como hacerlo, si me podrian ayudar, se los agradeceria.

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Hola, si eres nuevo te recomiendo que primero aprendas a hacer cosas más sencillas y cuando ya tengas una base te pongas a usar librerías como ésta, que requieren tener un mínimo conocimiento previo de cómo funciona Android.

  • http://gravatar.com/zantiago12 zantiago12

    Ok, perfecto. He hecho varias apps basicas para empresas, por eso me considero nuevo porque no he tratado con librerias ni nada externo ya que hago los programas desde cero guardando las clases.

    Solo quisiera cambiar el diseño de estas apps ;)

    • http://www.forgottenprojects.com/ Fernando F. Gallego

      Entonces deberías poder seguir el artículo, si no me dices qué problemas encuentras no te puedo ayudar.

  • Irving

    Disculpa soy nuevo en ésto, ¿cómo instalo la librería en mi proyecto?

  • Francisco Hdez.

    Gracias por la introducción. Quiero implementar el menú lateral en varias actividades, me gustaría saber cómo se realizar la implementación. Saludos!

  • Víctor

    Hola,

    Puedes poner un ejemplo del código que combina la librería SlidingMenu con la sherlActionBarSherlock

    Gracias

  • Luis Starlin Batista Tavarez

    me gustaría hacer un menú así como el de youtube,que cuando les da clic este se acopla al lado izquierdo del navegador.Pero si el navegador esta minimizado este menú se queda como flotando.Ayuda,please.