Notifications. Кастомні сповіщення

Android надає нам можливість самим створити layout для повідомлень.

Розглянемо простий приклад:

layout/notification.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/root"
   android:layout_width="match_parent"
   android:layout_height="64dp"
   android:orientation="horizontal">
 
   <TextView
       android:id="@+id/textView"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginStart="8dp"
       android:layout_marginTop="8dp"
       android:text="TextView"
       android:textAppearance="@style/TextAppearance.Compat.Notification.Title" />
 
</LinearLayout>

Висота 64dp - стандартна висота повідомлення.

Будемо показувати тільки TextView. Рекомендується використовувати @style/TextAppearance.Compat.Notification.* стилі, щоб ваш текст коректно відображався на будь-якій версії Android.

Код білдера повідомлення має такий вигляд:

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.textView, "Custom notification text");
remoteViews.setOnClickPendingIntent(R.id.root, rootPendingIntent);
 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
       .setSmallIcon(R.mipmap.ic_launcher)
       .setContent(remoteViews);

Створюємо RemoteViews з layout файлу.

Методом setTextViewText поміщаємо текст у View c id = R.id.textView.

А методом setOnClickPendingIntent вказуємо PendingIntent, який буде викликаний при натисканні на View з id = R.id.root. У нашому прикладі root - це кореневий LinearLayout. Відповідно під час натискання на сповіщення, буде використано цей PendingIntent, щоб запустити Activity/Service/BroadcastReceiver.

У білдері залишається необхідність вказати іконку, яку буде видно в області повідомлень. А ось методи setContentTitle і setContentText не потрібні. Замість них використовуємо setContent і передаємо туди створений RemoteViews.

У результаті побачимо своє повідомлення

Для порівняння поруч відображено стандартне повідомлення.

Є ще один, новіший, спосіб створення кастомного повідомлення - використання стилю DecoratedCustomViewStyle.

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.textView, "Custom notification text");
remoteViews.setOnClickPendingIntent(R.id.root, rootPendingIntent);
 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
       .setSmallIcon(R.mipmap.ic_launcher)
       .setCustomContentView(remoteViews)
       .setStyle(new NotificationCompat.DecoratedCustomViewStyle());

Відмінність від старого способу в тому, що ми викликаємо метод setCustomContentView, а не setContent, і використовуємо стиль DecoratedCustomViewStyle.

Результат:

Зверніть увагу, що в цьому разі кастомізується вже не все сповіщення, а тільки його зміст. А інші частини сповіщення, як-от іконка, час або action кнопки залишаться на своїх місцях.

Використання DecoratedCustomViewStyle дає нам можливість кастомізувати і розширене повідомлення.

Приклад

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.textView, "Custom notification text");
remoteViews.setOnClickPendingIntent(R.id.root, rootPendingIntent);
 
RemoteViews remoteViewsExtended = new RemoteViews(getPackageName(), R.layout.extended_notification);
remoteViewsExtended.setTextViewText(R.id.textView, "Extended custom notification text");
remoteViewsExtended.setOnClickPendingIntent(R.id.root, rootPendingIntent);
 
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
       .setSmallIcon(R.mipmap.ic_launcher)
       .setCustomContentView(remoteViews)
       .setCustomBigContentView(remoteViewsExtended)
       .setStyle(new NotificationCompat.DecoratedCustomViewStyle());

Тут ми кастомізуємо і звичайний вигляд повідомлення (setCustomContentView), і розширений (setCustomBigContentView).

Результат:

Висота layout розширеного повідомлення має бути не більшою за 256dp.