Создаём уведомления в Android. Часть 5. Свой дизайн уведомления

Стандартный дизайн уведомлений подходит только для оповещения пользователя о чём-либо в виде текста.

В стандартном макете можно задействовать графический интерфейс пользователя, но его возможности очень сильно ограничены. Чтобы получить возможность более гибкой настройки внешнего вида уведомления и более широкий функционал для интерфейса пользователя лучше создавать собственные макеты.

Основные принципы

Рассмотрим создание собственного макета на простом примере, который содержит текстовую надпись и кнопку.

Разметка макета:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        <TextView
                android:id="@+id/textViewNotification"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:text="@string/custom_notify_test"
                app:layout_constraintTop_toTopOf="parent" />
        <Button
                android:id="@+id/notify_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="8dp"
                android:text="@string/ok" />
    </LinearLayout>
</LinearLayout>

При создании уведомления получаем макет как RemoteViews:

val notificationLayout = RemoteViews(packageName, R.layout.custom_notification_layout)

И передаём в NotifictionBuilder через метод setContent (на данный момент устарел (deprecated)).

builder.setContentIntent(contentIntent)
    .setSmallIcon(R.drawable.ic_launcher_foreground)
    .setCustomContentView(notificationLayout)

Или setCustomContentView с использованием стиля DecoratedCustomViewStyle ()

builder.setContentIntent(contentIntent)
    .setSmallIcon(R.drawable.ic_launcher_foreground)
    .setStyle(Notification.DecoratedCustomViewStyle())
    .setCustomContentView(notificationLayout)

Обратите внимание на отсутствие методов, задающих заголовок, текс и значок. Теперь всё это определяется макетом.

Дальнейшие действия не отличаются от обычного уведомления.

Важно отметить, что далеко не все контейнеры и элементы управления могут быть использованы в макетах уведомлений. При создании макета доступны только: FrameLayout, LinearLayout, RelativeLayout, GridLayout, AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView и AdapterViewFlipper. Подробнее можно посмотреть в документации [1].

Это нужно обязательно учитывать при разработке дизайна уведомления.

Редактирование и добавление функционала

Параметры элементов макета могут быть изменены в процессе работы приложения. Для этого используются специальные методы объекта RemoteViews.

Так, например тестовую надпись можно изменить при помощи метода setTextViewText.

notificationLayout.setTextViewText(R.id.textViewNotification,"TEST 2")

Подобные методы предусмотрены и для других поддерживаемых элементов управления (см. [1]).

Что касается функционала, то для макета предусмотрена только обработка события onClick и то посредством PendingIntent. Но, для этого нужно не только соответствующим образом сконфигурировать сам PendingIntent, но, и реализовать его обработку.

Вначале создадим BroadcastReceiver, который будет получать данные из Intent. В нашем тестовом примере данные буду просто выводиться в Logcat.

class TestReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if ((intent != null) and (context != null)) {
            if (intent?.action.equals(MainActivity.ACTION_ID)) {
                val intentData = intent.getStringExtra("test_message");
                Log.e(context.packageName,intentData)
            }
        }
    }
}

Log.e в данном случае используется только для того, чтобы сделать наше сообщение более заметным среди общей массы того, что система выводит в Logcat.

Зарегистрируем BroadcastReceiver в манифесте приложения.

<receiver
&nbsp;&nbsp;&nbsp; android:name=".TestReceiver"
&nbsp;&nbsp;&nbsp; android:enabled="true"
&nbsp;&nbsp;&nbsp; android:exported="true">
&nbsp;&nbsp;&nbsp; <intent-filter>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <action android:name="com.example.notifysample.TEST_ACTION" />
&nbsp;&nbsp;&nbsp; </intent-filter>
</receiver>

Далее создаём константу, которая содержит имя действия для BroadcastReceiver.

public class NotificationActions {
    companion object {
        public const val ACTION_ID = "com.example.notifysample.TEST_ACTION"
    }
}

В нашем случае для простоты мы создадим её прямо в Activity. Но, в реальных приложениях лучше это делать в специальном интерфейсе.

Теперь создадим Intent, который будет содержать нужные данные и обернём его в PendingIntent.

val intent = Intent(this, TestReceiver::class.java)
intent.putExtra("test_message", "TEST MESSAGE")
intent.setAction(NotificationActions.ACTION_ID)
val flags = PendingIntent.FLAG_UPDATE_CURRENT
val pendingIntent = PendingIntent.getBroadcast(
    this,
    1,
    intent,
    flags
)

Цифра «1» обозначает так называемый requestCode. Этот параметр практически не используется системой, но для корректной работы желательно задавать каждому PeindingIntent собственное значение этого параметра (обязательно отличное от нуля).

Далее привязываем PendingIntent к кнопке нашего макета при помощи метода setOnClickPendingIntent.

notificationLayout.setOnClickPendingIntent(R.id.notify_btn, pendingIntent)

На этом процесс добавления функционала завершён.

При нажатии кнопки в уведомлении в Logcat теперь будет отображаться информация переданная через «test_message».

В случае необходимости можно поместить в макет несколько кнопок или других компонентов, которые имеют возможность обрабатывать событие onClick. К ним можно привязать как различные объекты PendingIntent, так и один общий для нескольких или для всех компонентов.

Также если нужно с помощью PendingIntent также можно запустить и новую Activity.

val intent = Intent(this, MyActivity::class.java)
val flags = PendingIntent.FLAG_UPDATE_CURRENT
val pendingIntent = PendingIntent.getActivity(
    this,
    1,
    intent,
    flags
)

Другие статьи из этого цикла

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *