DesarrolloLibre

Desarrollo Web, Android, juegos y mucho más

Categorias
¡Actualizado el 17-08-2017!

En esta entrada veremos cómo crear una notificación personalizada con Android empleando como ambiente de desarrollo de software Android Studio.

¿A qué nos referimos con notificación personalizada?

A que emplearemos una vista desarrollada desde cero para tal fin; incluso emplearemos una serie de botones los cuales pueden ejercer sus acciones sobre la actividad que crea dicha notificación, servicios o Broadcast que definieramos.

Creando la notificación personalizada

Los intent en el paso de datos

El código de la vista está un poco más adelante en la entrada, pero por ahora indicaremos los primeros pasos para crear una notificación en Android.

Intent intent = new Intent(getApplicationContext(), MusicService.class);
noBundle.putInt("accion", 1);//This is the value I want to pass
intent.putExtras(noBundle);
PendingIntent pendingIntent = PendingIntent.getService(ListActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibAccion, pendingIntent);

Expliquemos el propósito de cada componente del código presentado anteriormente:

Muy importante la bandera PendingIntent.FLAG_UPDATE_CURRENT que en conjunto con:

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:launchMode="singleTop"
    android:screenOrientation="portrait">
...
</activity>

Indica que la actividad existe actualmente (por defecto la MainActivity es la primera actividad que inició) y el android:launchMode="singleTop" y es una forma de indicar que la instancia de la actividad sea única, aunque existen otras formas como puedes consultar en el siguiente enlace (en otras palabras significa actualizar la instancia de la actividad que está en ejecución actualmente).

Definiendo las acciones de la vista personalizada

Cómo son tres botones, necesitamos tres Intents diferentes y todo lo que esto conlleva, por lo tanto ahora multiplicamos esto por tres:

Intent intent = new Intent(getApplicationContext(), MusicService.class);
noBundle.putInt("accion", 1);//This is the value I want to pass
intent.putExtras(noBundle);
PendingIntent pendingIntent = PendingIntent.getService(ListActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibAccion, pendingIntent);

Bundle noBundle2 = new Bundle();
noBundle2.putInt("accion", 2);//This is the value I want to pass
Intent intent2 = new Intent(getApplicationContext(), ListActivity.class);
intent2.putExtras(noBundle2);
PendingIntent pendingIntent2 = PendingIntent.getActivity(ListActivity.this, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibQuitar, pendingIntent2);

Bundle noBundle3 = new Bundle();
noBundle3.putInt("accion", 3);//This is the value I want to pass
Intent intent3 = new Intent(getApplicationContext(), ListActivity.class);
intent3.putExtras(noBundle3);
PendingIntent pendingIntent3 = PendingIntent.getActivity(ListActivity.this, 3, intent3, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibSiguiente, pendingIntent3);

Lanzando la notificación personalizada

Ahora podemos crear nuestra notificación; primero el administrador de la notificación (NotificationManager) que como su nombre indica y mediante una instancia de esta clase podemos lanzar la notificación con el NotificationCompat.Builde podemos establecer las propiedades de la notificación y crear la notificación propiamente dicha; por ejemplo indicamos el título, subtítulo el icono y el PendingIntent cuya acción será ejercida al momento de que el usuario realice un clic sobre la notificación:

NotificationManager nManager;
NotificationCompat.Builder nBuilder;
RemoteViews remoteView;

PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
        new Intent(this, ListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);

nBuilder = new NotificationCompat.Builder(this)
        .setContentTitle(getString(R.string.app_name))
        .setTicker(getString(R.string.app_name))
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentIntent(contentIntent)
        .setOngoing(false)
        .setAutoCancel(false);

Como podemos apreciar, al momento de crear la notificación establecemos varios parámetros como el contenido (título), icono y el mismo Intent que definimos anteriormente.

Ahora falta especificar cual es la vista en cuestión (la que posee el diseño que creamos con los tres botones), esto lo hacemos mediante un RemoteViews:

remoteView = new RemoteViews(getPackageName(), R.layout.notification_layout);
remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
remoteView.setTextViewText(R.id.title, "Título");
remoteView.setTextViewText(R.id.text,"Nombre");

Como podemos ver en el código anterior, accedemos a cada una de sus componentes y establecemos un valor que para efectos de este tutorial son fijos.

En nuestro caso la vista tiene el siguiente contenido:

<?xml version="1.0" encoding="UTF-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#333333"
    android:orientation="vertical"
    android:weightSum="1">

    <LinearLayout
        android:id="@+id/right"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/imagenotileft"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:background="@mipmap/ic_launcher" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:orientation="vertical">

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                android:layout_marginTop="9dp"
                android:textColor="#FFFFFF"
                android:textSize="16sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/title"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                android:textColor="#EEEEEE"
                android:textSize="14sp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="horizontal">

            <ImageButton
                android:id="@+id/ibAtras"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@null"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_av_skip_previous" />

            <ImageButton
                android:id="@+id/ibAccion"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@null"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_ic_play_pause" />

            <ImageButton
                android:id="@+id/ibSiguiente"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@null"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_av_skip_next" />

            <Button
                android:id="@+id/ibQuitar"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@null"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:text="X"
                android:textColor="#444444"
                android:textSize="16sp" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
Notificación Personalizada

Finalmente establecemos la vista anterior y lanzamos la notificación:

        setListeners(remoteView);
        nBuilder.setContent(remoteView);

        nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        nManager.notify(2, nBuilder.build());

Replicar las notificaciones en Android

Hasta ahora hemos visto cómo crear una notificación con un layout personalizado y cómo interactuar con los elementos que definimos en este layout como Buttons o ImageView, etc; en esta segunda parte de esta entrada veremos cómo crear notificaciones que se puedan replicar; esta es una acción muy empleada en aplicaciones de mensajería como Hangout de Google o el mismo Whatsapp en Android.

Compatibilidad entre las notificaciones

Las notificaciones tienen una gran compatibilidad hacia atrás empleando la clase NotificationCompat.Builder y podemos emplear muchisimas opciones que tienen desde prioridad hasta estilos pero debemos tener muy presentes que funcionalidades empleamos ya que algunas funciones en específico están provistas solo para versiones superiores de Android superiores a la 4.1.

Creando el medio para el pase de datos entre componentes: PendingIntent

Lo primero que debemos hacer es crear un PendingIntent y asociar el Intent que es el medio empleado para pasar datos de un componente; estos componentes no solo pueden ser Actividades o Fragments, también pueden ser otros como Broadcast para realizar actualizaciones en segundo plano sin la necesidad de invocar a la actividad; aunque para esto debemos emplear Android N en adelante; para no extender demasiada esta entrada, nos iremos por el caso en que se invoca a la actividad.

El PendingIntent es el mecanismo existente que tenemos para pasar datos entre distintos componentes como actividades, broadcast o servicios que embebe dentro del mismo los datos que queremos pasar a estos componentes (en caso de que se desee pasar un dato):

RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
       .setLabel(replyLabel)
       .build();

Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.setAction(KEY_TEXT_REPLY);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent replyPendingIntent =
       stackBuilder.getPendingIntent(
               0,
               PendingIntent.FLAG_UPDATE_CURRENT
       );

El método setAction permite asociar el nombre del dato a pasar, que en este caso será el texto que el usuario suministre en el campo de réplica y con este nombre accedemos al texto que ingreso el usuario en el onCreate de nuestra actividad:

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

   Intent intent = getIntent();

   if (KEY_TEXT_REPLY.equals(intent.getAction())) {

       Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
       if (remoteInput != null) {
           Log.i("REPLICA", "" + remoteInput.getCharSequence(KEY_TEXT_REPLY));
       }

   }
   replyNotification();
}

Con el método RemoteInput indicamos que crearemos un mecanismo para el pase de datos dentro del PendingIntent; además de asociamos el label o texto que va a aparecer en el campo de la réplica.

Creando la notificación replica

Asociamos el PendingIntent que creamos anteriormente:


NotificationCompat.Action action =
       new NotificationCompat.Action.Builder(R.mipmap.ic_launcher,
               "Replicar", replyPendingIntent)
               .addRemoteInput(remoteInput)
               .build();

Creando la notificación replica

Creamos la notificación estableciendo el contenido de la misma: icono representativo, título, contenido y la acción que configuramos en el bloque anterior:

NotificationCompat.Builder newMessageNotification =
       new NotificationCompat.Builder(MainActivity.this)
               .setSmallIcon(R.mipmap.ic_launcher)
               .setContentTitle("My notification")
               .setContentText("Hello World!")
               .addAction(action);

Finalmente lanzamos la notificación junto con las acción que configuramos en los pasos anteriores a través del método build():

NotificationManagerCompat notificationManager =
       NotificationManagerCompat.from(MainActivity.this);
notificationManager.notify(NOTIFICATION_ID, newMessageNotification.build());

El método completo queda como:

    public void replyNotification() {
        RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
                .setLabel(replyLabel)
                .build();

        Intent resultIntent = new Intent(this, MainActivity.class);
        resultIntent.setAction(KEY_TEXT_REPLY);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent replyPendingIntent =
                stackBuilder.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

        NotificationCompat.Action action =
                new NotificationCompat.Action.Builder(R.mipmap.ic_launcher,
                        "Replicar", replyPendingIntent)
                        .addRemoteInput(remoteInput)
                        .build();


        NotificationCompat.Builder newMessageNotification =
                new NotificationCompat.Builder(MainActivity.this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle("My notification")
                        .setContentText("Hello World!")
                        .addAction(action);

        NotificationManagerCompat notificationManager =
                NotificationManagerCompat.from(MainActivity.this);
        notificationManager.notify(NOTIFICATION_ID, newMessageNotification.build());
    }

Finalmente el resultado es el siguiente:

Notificación de Réplica en android

Enlaces de referencia:


Publicidad

Give me for a beer!

Algunos recursos que te pueden interesar

Creando increibles Drawer en Android con MaterialDrawer

Creando increibles Drawer en Android con MaterialDrawer

Librería oficial de PayPal para Android

Librería oficial de PayPal  para Android

Generador de launcher para Android sin padding

Generador de launcher para Android sin padding

Algunos artículos que te pueden interesar

¿Cómo firmar las aplicaciones Android?

¿Cómo firmar las aplicaciones Android?

En general la finalidad de programar aplicaciones es para colocarlas en fase de producción en algún momento de su ciclo de vida; en Android este concepto vendría siendo algo así como publicarlas; para poder subirlas a la Google Play debemos de firmar nues

Andrés Cruz 05-11-2013

Creando un FloatingActionButton en Android (Lib de Soporte)

Creando un FloatingActionButton en Android (Lib de Soporte)

Esta entrada ofrece una introducción para Android Studio; veremos como instalarlo, sus herramientas, crear proyectos, los archivos Gradle, combinación de teclas, etc.

Andrés Cruz 24-08-2015

Api.ai, el asistente de voz para aplicaciones y dispositivos móviles echa a tu medida

Api.ai, el asistente de voz para aplicaciones y dispositivos móviles echa a tu medida

Api.ai es un asistente de voz que permite crear nuestros propios asistentes de voz mediante las SDKs para Android, IOS y Web.

Andrés Cruz 01-10-2014