Фон уведомлений в Android Lollipop белый. Как я могу его изменить?

Я хочу показать уведомление для сообщения в своем приложении. В предыдущих версиях Android все в порядке, но в Lollipop фон уведомлений белый. Я использовал этот XML-код для своего макета уведомлений в layout_message_notification.xml :

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_messageNotification" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent"> <LinearLayout android:layout_width="0dp" android:layout_weight=".2" android:layout_height="wrap_content" android:background="@android:color/transparent"> <ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" android:scaleType="fitCenter" android:src="@drawable/message_icon"/> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_weight=".8" android:layout_height="wrap_content" android:background="@android:color/transparent"> <TextView android:id="@+id/textView_notification_title" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="right|center_vertical" android:layout_margin="15dp"/> </LinearLayout> </LinearLayout> 

Мое уведомление в леденец показано следующим образом: Стиль уведомления в леденец

Как сделать фоновое уведомление темным или прозрачным, как в предыдущих версиях Android?

Solutions Collecting From Web of "Фон уведомлений в Android Lollipop белый. Как я могу его изменить?"

В конце концов, если вы хотите следовать официальной спецификации материала

Всегда используйте ресурсы стиля для текста настраиваемого уведомления.

И использовать пользовательский макет ваших уведомлений, вы, возможно, считаете, что не переопределяете фон по умолчанию, а изменяете стиль текста из-за версии API. Вы можете добиться этого, создав два файла стиля ресурса и используя их в соответствии с текущей версией API:

Значения-V21 / notification_styles.xml

 <?xml version="1.0" encoding="utf-8"?> <resources> <!-- according to official recommendation custom notifications should has the same text style as default one--> <style name="NotificationHeader" parent="@android:style/TextAppearance.Material.Notification.Title" /> <style name="NotificationContent" parent="@android:style/TextAppearance.Material.Notification.Line2" /> </resources> 

а также

Значения / notification_styles.xml

 <?xml version="1.0" encoding="utf-8"?> <resources> <!-- according to official recommendation custom notifications should has the same text style as default one--> <style name="NotificationHeader" parent="@android:style/TextAppearance.StatusBar.EventContent.Title" /> <style name="NotificationContent" parent="@android:style/TextAppearance.StatusBar.EventContent" /> </resources> 

Этот ответ описывает хакерский метод изменения цвета фона уведомлений.
Обратите внимание: это недокументированное обходное решение ; Он основан на отражении и может быть нарушен на пользовательских прошивках; Он применим только к версиям Android Lollipop и Marshmallow; Он не будет работать в Android N и более высоких версиях. Я бы рекомендовал придерживаться цвета по умолчанию, если у вас нет серьезной причины его избежать.

ЗАЧЕМ
Не существует законного способа установки цвета фона для пользовательского уведомления. Google решил, что уведомления должны быть белого или светло-серого в зависимости от его приоритета в соответствии с Material Design . Однако Google также сделал два исключения из этого правила:

  1. Уведомления для старых приложений отображаются с черным фоном;
  2. Уведомления, созданные с помощью MediaStyle могут иметь любой цвет.

В результате второго исключения такое ограничение выглядит нелогичным и необоснованным, и это единственное возможное оправдание, по которому вы по-прежнему хотите использовать собственный цвет вместо того, который рекомендуется (или принудительно?) Google.

ЧТО ВНУТРИ
Давайте посмотрим на BaseStatusBar чтобы узнать, как это ограничение наложено. Единственное место, где вычисляется фоновый цвет для уведомления, – метод applyColorsAndBackgrounds .
Первая ветвь оператора if предназначена для устаревших приложений. Единственный способ получить здесь – установить целевой SDK вашего приложения ниже Build.VERSION_CODES.LOLLIPOP . В этом случае фон станет черным.
Нам интересна инструкция entry.row.setTintColor . Чтобы достичь этого, необходимо пройти несколько проверок, включая тот, который содержится в методе isMediaNotification . Вот они:

  1. Уведомление должно содержать как обычные, так и большие представления.
  2. На верхнем уровне в обоих представлениях должен быть com.android.internal.R.id.status_bar_latest_event_content как его идентификатор.
  3. Большой макет должен содержать виджет с com.android.internal.R.id.media_actions как его идентификатор.

КАК
Наиболее проблематичными являются идентификаторы, если они объявлены во внутренних ресурсах и не могут быть доступны из XML-макета приложения.
Вторая проблема заключается в том, что RemoteViews используемые в уведомлении, являются всего лишь идентификатором ресурса компоновки в приложении и не могут быть сконструированы в коде. В результате мы не можем добавлять макеты с идентификаторами, необходимыми для прохождения всех проверок, упомянутых выше.

Однако Google добавил методы addView и removeAllViews в RemoteViews для своих нужд (они используются в уведомлении MediaStyle ) и забыли сделать их частными.

Итак, окончательная идея проста:

  • Создать уведомление на основе внутреннего макета, определенного Google (пройти 2-й чек)
  • Удалить все с помощью removeAllViews
  • Добавьте наш собственный макет с помощью addView
  • Специальный случай для большого вида: добавьте макет, определенный Google, который содержит media_actions для невидимого просмотра внутри нашего пользовательского макета (чтобы пройти 3-й чек)

Недостатки:

  • Раздувание неиспользуемых видов (они удаляются сразу после раздувания)
  • Сложная и более глубокая иерархия раскладки

РЕШЕНИЕ
Наше FrameLayout большое представление должно содержать FrameLayout с FrameLayout android.R.id.empty как его идентификатор. Фактически, любой идентификатор может использоваться здесь, просто убедитесь, что вы ссылаетесь на тот же ID в коде (см. Ниже).

 // We need theese ids to use internal Android resources int topId = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "android"); int topBigLayout = Resources.getSystem().getIdentifier("notification_template_material_big_media_narrow", "layout", "android"); int topSmallLayout = Resources.getSystem().getIdentifier("notification_template_material_media", "layout", "android"); RemoteViews viewSmall = ...; // Create our custom view here RemoteViews viewBig = ...; // Create our custom big view here // This is invisible inner view - to have media_actions in hierarchy RemoteViews innerTopView = new RemoteViews("android", topBigLayout); viewBig.addView(android.R.id.empty, innerTopView); // This should be on top - we need status_bar_latest_event_content as top layout RemoteViews topBigView = new RemoteViews("android", topBigLayout); topBigView.removeAllViews(topId); topBigView.addView(topId, viewBig); // This should be on top - we need status_bar_latest_event_content as top layout RemoteViews topSmallView = new RemoteViews("android", topSmallLayout); topSmallView.removeAllViews(topId); topSmallView.addView(topId, viewSmall); Notification.Builder builder = new Notification.Builder(this); builder.setSmallIcon(R.drawable.ic_notification) .setTicker("Some text") .setColor(0xff000000) // The desired color! .setContent(topSmallView); Notification n = builder.build(); n.bigContentView = topBigView; // Use our notification "n" here as usual 

Можно использовать другой макет вместо notification_template_material_big_media_narrow на верхнем уровне, чтобы манипулировать высотой большого вида. Найдите подходящий файл среди файлов notification_template_xxx.xml. Но не стоит забывать о том, что media_actions в иерархии.

Это правильное поведение.

Если вы хотите иметь прямой контроль над этим аспектом, я предлагаю вам сделать следующее:

  • Создайте альтернативную версию layout_message_notification.xml внутри папки res/layout-v21

  • Немного измените эту новую версию, изменив цвет фона внешнего макета :

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_messageNotification" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/gray"> //...