Diseño Android: Menu inferior Bottom Navigation con Material Components

logo android

La especificación de Material Design incluye un tipo de menú de navegación que en los últimos tiempos está adquiriendo gran popularidad, y que encontramos en aplicaciones tan populares como Spotify o Instagram, además de en las propias de Google (YouTube, Google Play…). Se trata de una barra de navegación situada en la parte inferior de la pantalla que muestra entre tres y cinco elementos de navegación. Asimismo, en algunas aplicaciones esté menú se complementa con un menú lateral, recomendado cuando existan más de cinco destinos de navegación.

bottomnavigationview examples

Google proporcionó una implementación de este componente con el widget BottomNavigationView en el módulo design de la librería de compatibilidad, obsoleta desde 2018. En el presente artículo vamos a utilizar la versión «buena» de BottomNavigationView: la disponible en Material Components For Android. Aprenderás a crear una barra de navegación con sus funcionalidades más habituales.

  1. Proyecto de ejemplo con BottomNavigationView
  2. Implementando la navegación con un listener
  3. Badges (insignias)
  4. Ocultar\mostrar al hacer scroll
  5. Código de ejemplo

Proyecto de ejemplo con BottomNavigationView

La versión actual del proyecto de ejemplo utiliza lo último disponible en febrero de 2023:

  • Android API 33
  • Gradle 7.5 (requiere Java 11)
  • Android Studio Electric Eel
  • Material Components 1.8

El lenguaje es Java, pero veremos poco código y muy simple, así que no tendrás problemas en adaptarlo a Kotlin si prefieres este lenguaje.

Este es el build.properties:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 33

    defaultConfig {
        applicationId "com.danielme.android.bottomnavigation"
        minSdkVersion 26
        targetSdkVersion 33
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation "androidx.recyclerview:recyclerview:1.2.1"
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.0'
}

El proyecto, sencillo pero realista, consiste en una única Activity. Vamos primero con su layout. La primera versión —complicaremos un poco su diseño al final del artículo— muestra una Toolbar en la parte superior y el componente BottomNavigationView, ambos posicionados dentro de un ConstraintLayout:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
 
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

La línea 23 establece el menú de navegación. ¿Cómo lo creamos? Pues como cualquier menú estándar de Android. Aquí lo tienes (fichero /res/menu/bottom_nav_menu.xml):

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/page_home"
        android:icon="@drawable/baseline_home_black_24"
        android:title="@string/bottom_nav_home" />
    <item
        android:id="@+id/page_fav"
        android:icon="@drawable/baseline_favorite_black_24"
        android:title="@string/bottom_nav_fav" />
    <item
        android:id="@+id/page_search"
        android:icon="@drawable/baseline_search_black_24"
        android:title="@string/bottom_nav_search" />
    <item
        android:id="@+id/page_settings"
        android:icon="@drawable/baseline_app_settings_alt_black_24"
        android:title="@string/bottom_nav_settings" />
</menu>

He creado cuatro entradas de menú, cada una con título y un icono. Los iconos los he descargado de la página oficial de Material Design.

La activity no tiene ninguna complicación. Se limita a «inflar» el layout y establecer la Toolbar como ActionBar:

package com.danielme.android.bottomnavigation;

import android.os.Bundle;
import android.view.MenuItem;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;

import com.danielme.android.bottomnavigation.fragments.PageFragment;
import com.danielme.android.bottomnavigation.fragments.RecyclerViewFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setupToolbar();
  }

  private void setupToolbar() {
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
  }

}

El último elemento que nos falta es el tema gráfico de la aplicación. En el fichero /res/values/themes.xml declaramos como tema global de la aplicación uno de tipo DayNight de Material Components con soporte para tema claro y oscuro. En concreto, el que no se aplica a la ActionBar del sistema (estamos definiendo nuestra propia Toolbar). Como es habitual en mis tutoriales, me limitaré a declarar un color púrpura como el principal de la aplicación:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primaryDark</item>
        <item name="toolbarStyle">@style/Widget.MaterialComponents.Toolbar.PrimarySurface</item>
    </style>

</resources>

¡Listo! Si ejecutas el proyecto verás el menú.

android bottomnavigation default

Como puedes ver, las entradas del menú solo muestran el icono. El título queda reservado para el elemento seleccionado. Este comportamiento se cambia con la propiedad labelVisibilityMode:

  • app:labelVisibilityMode=»unlabeled«. Nunca se mostrará el texto del icono.
    android bottomnavigation unlabeled
  • app:labelVisibilityMode=»labeled«. Se muestra siempre el texto. Es el diseño más habitual.
    android bottomnavigation labeled

En lo que respecta a los colores, la barra se muestra con el color definido por la variable ?attr/colorSurface y el elemento seleccionado (icono y texto) se resalta con el color principal de la app. Los estilos son muy configurables; las propiedades personalizables se describen al final de la documentación oficial.

Implementando la navegación con un listener

Demósle vidillla al menú. Queremos que cada entrada muestre un fragment en el centro de la pantalla. Así, tendremos un auténtico menú de navegación.

Siempre usaremos un mismo fragment que mostrará en su centro el icono de la entrada del menú seleccionada. Este es su layout:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
 
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        tools:srcCompat="@drawable/baseline_app_settings_alt_black_48" />
 
</FrameLayout>

La creación la haremos con el típico «constructor estático» ya que un fragment debe crearse siempre utilizando su constructor vacío, a menos que trabajemos con FragmentFactory, y queremos una forma obvia de instanciarlo con el identificador del icono.

package com.danielme.android.bottomnavigation.fragments;
 
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
 
import com.danielme.android.bottomnavigation.R;
 
public class PageFragment extends Fragment {
 
  private static final String ARG_ICON = "ARG_ICON";
 
  public static PageFragment newInstance(@DrawableRes int iconId) {
    PageFragment frg = new PageFragment();
 
    Bundle args = new Bundle();
    args.putInt(ARG_ICON, iconId);
    frg.setArguments(args);
 
    return frg;
  }
 
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
          Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.fragment_page, container, false);
    layout.findViewById(R.id.imageView).setBackgroundResource(getArguments().getInt(ARG_ICON));
    return layout;
  } 

Añadimos un «contenedor» en la activity para insertar el fragment:

<com.google.android.material.appbar.MaterialToolbar
    android:id="@+id/toolbar"
   android:layout_width="match_parent"
   android:layout_height="?attr/actionBarSize"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
 
<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
    app:layout_constraintTop_toBottomOf="@id/toolbar" />
 
 
<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_navigation"

Ahora viene lo interesante. Recibimos la pulsación o toque en los elementos del menú en un listener de tipo OnNavigationItemSelectedListener si lo vinculamos al componente BottomNavigationView:

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  setupToolbar();
  setupBottomMenu();
}

private void setupBottomMenu() {
  bottomNavigationView = findViewById(R.id.bottom_navigation);
  bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
    switch (item.getItemId()) {
      case R.id.page_home:
        showFragment(PageFragment.newInstance(R.drawable.baseline_home_black_48));
        break;
      case R.id.page_fav:
        showFragment(PageFragment.newInstance(R.drawable.baseline_favorite_black_48));
        break;  
      case R.id.page_search:
        showFragment(PageFragment.newInstance(R.drawable.baseline_search_black_48));
        break;
      case R.id.page_settings:
        showFragment(PageFragment.newInstance(R.drawable.baseline_app_settings_alt_black_48));
        break;
      default:
        throw new IllegalArgumentException("item not implemented : " + item.getItemId());
    }
   return true;
  });
  //setear aquí para que el listener muestre el fragment inicial al cargarse la pantalla
  bottomNavigationView.setSelectedItemId(R.id.page_home);
}
 
private void showFragment(Fragment frg) {
   getSupportFragmentManager()
          .beginTransaction()
          .setCustomAnimations(R.anim.bottom_nav_enter, R.anim.bottom_nav_exit)
          .replace(R.id.container, frg)
          .commit();
 
}

La implementación del listener es sencilla. Se trata el típico switch que decide qué hacer según el elemento del menú que fue pulsado; en nuestro caso, instanciar y mostrar en pantalla un PageFragment con el icono adecuado. Eso sí, hay un pequeño detalle (línea 31) del que no podemos olvidarnos: al cargarse la activity hay que mostrar el fragment correspondiente al elemento del menú seleccionado por omisión.


Otro detalle a considerar: cuando rotamos la pantalla deberíamos conservar la selección actual para evitar que se muestre el fragment inicial. La técnica para conseguirlo es la habitual en estos casos. Consiste en sobrescribir el método onSaveInstanceState de la activity para guadar en un objeto Bundle lo que queramos. Esa información es la que recibe como argumento onCreate.

En esta implementación, guardo en el Bundle el identificador del item del menú seleccionado:

@Override
protected void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  outState.putInt(SELECTION, bottomNavigationView.getSelectedItemId());
}  

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setupToolbar();
    setupBottomMenu(savedInstanceState);
}
 
private void setupBottomMenu(Bundle savedInstanceState) {
  bottomNavigationView = findViewById(R.id.bottom_navigation);
  bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
   ...
    }
  });
   //setear aquí para que el listener muestre el fragment inicial al cargarse la pantalla
  if (savedInstanceState == null) {
    bottomNavigationView.setSelectedItemId(R.id.page_home);
  } else {
    bottomNavigationView.setSelectedItemId(savedInstanceState.getInt(SELECTION));
  }
}

Badges (insignias)

Las entradas de menú pueden mostrar en su parte superior derecha un pequeño indicador, llamado badge o insignia, para llamar la atención del usuario. El caso de uso más común es informar que en la sección de notificaciones existen mensajes pendientes de leer.

bottomnavigationview badge

Material Components provee un mecanismo de insignias perfectamente integrado con BottomNavigationView: llamando al método BottomNavigationView#getOrCreateBadge obtenemos un objeto BadgeDrawable asociado al item del menú que queramos. Con ese objeto mostraremos y ocultaremos a conveniencia el indicador del badge (método setVisible) para el item. También podemos lograr que el badge muestre un número (método setNumber) que indique, por ejemplo, las notificaciones pendientes de atender

Aquí tienes un ejemplo de los dos casos:

bottomNavigationView.getOrCreateBadge(R.id.page_fav).setNumber(1000);
bottomNavigationView.getOrCreateBadge(R.id.page_settings).setVisible(true);
android bottomnavigation badget

Ocultar\mostrar al hacer scroll

Aunque no lo he visto en muchas aplicaciones, Material Design contempla la posibilidad de ocultar\mostrar automáticamente la barra de navegación al realizarse scroll en el contenido principal de la pantalla. Este comportamiento lo proporciona la integración de BottomNavigationView con CoordinatorLayout. Se configura de forma parecida a otros componentes gráficos como los botones FAB o las estructuras basadas en AppbarLayout (toolbar con pestañas, imágenes de fondo, etc) que también proporcionan de serie integración directa con CoordinatorLayout.

En esta sección veremos cómo aplicar ese comportamiento a un ejemplo realista. Por ello, ampliemos la aplicación de ejemplo con un nuevo fragment que muestre un listado con un RecyclerView. Puesto que tengo publicado un par de tutoriales sobre RecyclerView, y no es algo relevante para el presente tutorial, me limito a mostrar el código:

1- Añadir la dependencia:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
}

2- Creamos el layout para el Fragment que contendrá el RecyclerView:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
 
</FrameLayout>

3- Cada fila del listado consiste en un TextView:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:gravity="center_vertical"
    android:minHeight="@dimen/list_height">
 
    <TextView
        android:id="@+id/textView"
        style="@android:style/TextAppearance.Medium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:paddingStart="@dimen/standard_margin"
        android:paddingEnd="@dimen/standard_margin"
        tools:text="item" />
</FrameLayout>

4- En el Adapter recibimos una lista de cadenas que mapeamos con el ViewHolder correspondiente al layout anterior:

package com.danielme.android.bottomnavigation.fragments;
 
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
import androidx.recyclerview.widget.RecyclerView;
 
import com.danielme.android.bottomnavigation.R;
 
import java.util.List;
 
class SimpleTextRecyclerViewAdapter extends RecyclerView.Adapter<TextViewHolder> {
 
  private final List<String> items;
  private final LayoutInflater inflater;
 
  SimpleTextRecyclerViewAdapter(Context context, List<String> items) {
    this.inflater = LayoutInflater.from(context);
    this.items = items;
  }
 
  @Override
  public TextViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflater.inflate(R.layout.row_recycler_view, parent, false);
    return new TextViewHolder(view);
  }
 
  @Override
  public int getItemCount() {
    return items.size();
  }
 
  @Override
  public void onBindViewHolder(TextViewHolder holder, int position) {
    holder.bindText(items.get(position));
  }
 
}
package com.danielme.android.bottomnavigation.fragments;
 
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
 
import androidx.recyclerview.widget.RecyclerView;
 
import com.danielme.android.bottomnavigation.R;
 
class TextViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
 
  private final TextView textView;
 
  TextViewHolder(View itemView) {
    super(itemView);
    textView = itemView.findViewById(R.id.textView);
    itemView.setOnClickListener(this);
  }
 
  void bindText(String text) {
    textView.setText(text);
  }
 
  @Override
  public void onClick(View view) {
    Toast.makeText(view.getContext(), textView.getText(), Toast.LENGTH_SHORT).show();
  }
 

5- La implementación del fragment propiamente dicho que crea una lista de cadenas para el adapter y le pone un divider al RecyclerView:

package com.danielme.android.bottomnavigation.fragments;
 
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
 
import com.danielme.android.bottomnavigation.R;
 
import java.util.ArrayList;
import java.util.List;
 
public class RecyclerViewFragment extends Fragment {
 
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
          Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.fragment_recycler_view, container, false);
 
    RecyclerView recyclerView = layout.findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 
    List<String> items = new ArrayList<>();
    for (int i = 0; i < 25; i++) {
      items.add("item " + i);
    }
 
    recyclerView.setAdapter(new SimpleTextRecyclerViewAdapter(getContext(), items));
 
    DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
            DividerItemDecoration.VERTICAL);
    recyclerView.addItemDecoration(dividerItemDecoration);
 
    return layout;
  }
 
}

6- Para mostrar RecyclerViewFragment añadimos un botón a la barra de navegación:

<item
        android:id="@+id/page_list"
        android:icon="@drawable/baseline_list_black_24"
        android:title="@string/bottom_nav_list" />

7- Finalizamos el desarrollo lanzando el fragment dentro del listener del NavigationBottomView:

bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
     switch (item.getItemId()) {
       case R.id.page_home:
         showFragment(PageFragment.newInstance(R.drawable.baseline_home_black_48));
         break;
       case R.id.page_list:
         showFragment(new RecyclerViewFragment());
         break;
       ...

Y ahora vamos con lo importante. Para que el menú se oculté de manera automática al deslizarse el listado, recurrimos como ya dije a la «magia» de CoordinatorLayout. Tenemos que refactorizar el layout de la activity de tal modo que nuestro BottomNavigationView sea hijo directo del mismo:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatort"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
 
        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar"
            style="@style/AppTheme.ToolbarMain" />
 
        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
 
    </LinearLayout>
 
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:labelVisibilityMode="labeled"
        app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
        app:menu="@menu/bottom_nav_menu" />
 
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Fíjate en la línea resaltada: informa a BottomNavigationView cómo debe actuar ante el scroll.

Nos ha bastado un pequeño cambio en el layout para conseguir nuestro objetivo.

¿Quieres que también se oculte la Toolbar? Solo tienes que ubicarla dentro de un AppBarLayout, otro elemento compatible con CoordinatorLayout:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatort"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar"
            style="@style/AppTheme.ToolbarMain"
            app:layout_scrollFlags="scroll|enterAlways" />
 
    </com.google.android.material.appbar.AppBarLayout>
 
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
 
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:labelVisibilityMode="labeled"
        app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
        app:menu="@menu/bottom_nav_menu" />
 
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Este video muestra resultado final del proyecto de ejemplo, tal y como lo encontrarás en GitHub.

Código de ejemplo

El proyecto de ejemplo se encuentra en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.