安卓棒棒糖系统中通知背景是白色的。我该如何修改它?

13

我希望在我的应用程序中为一条消息显示通知。在之前的Android版本中一切都很好,但在Lollipop中,通知背景是白色的。 我在layout_message_notification.xml中使用了这个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>

我的Lollipop系统中通知的样式如下所示: notification style in lollipop

我该如何使通知背景变暗或透明,像之前的Android版本一样?

3个回答

8
本答案描述了一种改变通知背景颜色的hacky方法。
请注意:这是一种未经记录的解决方法;它基于反射,可能在自定义固件上失效;它仅适用于Android Lollipop和Marshmallow版本;它在Android N及以上版本上不起作用。我建议除非你有严重的理由避免使用默认颜色,否则最好坚持使用默认颜色。 为什么
没有合法的方法来设置自定义通知的背景颜色。根据Material Design,Google认为通知必须是白色或浅灰色,取决于其优先级。然而,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 作为其ID。
  3. 大布局必须包含一个带有 com.android.internal.R.id.media_actions 作为其ID的小部件。

HOW
最棘手的问题是ID,因为它们在内部资源中声明,无法从应用程序的布局XML中访问。
第二个问题是通知中使用的 RemoteViews 只是应用程序中布局资源的ID,不能在代码中构建。因此,我们无法添加具有所需ID以通过上述所有检查的布局。

然而,谷歌为其需要(它们在 MediaStyle 通知中使用)将 addViewremoveAllViews 方法添加到了 RemoteViews 中,并忘记将它们设置为私有。

因此,最终的想法很简单:

  • 基于Google定义的内部布局构建通知(以通过第二个检查)
  • 使用removeAllViews删除所有内容
  • 使用addView添加我们自定义的布局
  • 针对大视图的特殊情况:将包含media_actions的Google定义布局添加到我们自定义布局中不可见的视图中(以通过第三个检查)

缺点:

  • 填充未使用的视图(它们在填充后立即被删除)
  • 复杂和更深的布局层次结构

解决方案
我们自定义的大视图必须包含带有android.R.id.empty作为其ID的FrameLayout。实际上,任何ID都可以在此处使用,只需确保您在代码中引用相同的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放入层次结构中。


7

如果您想遵循官方材料设计的规范,可以参考此链接

始终使用样式资源来设置自定义通知的文本

如果您使用自定义通知布局,可以考虑不覆盖默认背景,而是根据API版本更改文本样式。 您可以通过创建两个资源样式文件并根据当前API版本使用它们来实现:

values-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>

and

values/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>

1
是的,但是如何将通知的背景设置为与主题相同?您提供的内容仅设置了通知标题和正文中的文本。在Lollipop中,自定义通知的背景仍然是白色的。您需要使用android:background来设置它吗? - Alex Bitek

3

这是通知的正确行为。

如果您想对此方面进行直接控制,建议按照以下步骤操作:

  • res/layout-v21 文件夹中创建 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/gray">
//...

是的,终于做到了!但我希望能找到更好的解决方案!谢谢。 - Mansour
2
在此处分配背景颜色并不是一个好主意,因为:
  1. 它会覆盖通知行的圆角(不适用于HTC - 他们改变了这种风格)
  2. 在调整通知大小时,仍然可以看到底层通知行布局的白色颜色。这在锁屏界面上尤其明显。即使没有大的通知视图。
- Stanislav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接