android - Android Lollipop 中的通知背景是白色的。我怎样才能改变它?

标签 android background notifications android-5.0-lollipop transparent

我想在我的应用程序中显示消息通知。在以前的 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 版本中一样?

最佳答案

这个答案描述了 哈克更改通知背景颜色的方法。
注意:这是一个未记录的解决方法 ;它基于反射,可能会在自定义固件上被破坏;仅适用于 Android Lollipop 和 Marshmallow 版本;它不会工作在 Android N 及更高版本上。我建议坚持使用默认颜色,除非您有充分的理由避免使用它。

为什么
没有为自定义通知设置背景颜色的合法方法。 Google 根据 Material Design 决定通知必须是白色或浅灰色,具体取决于其优先级。然而,谷歌也对这条规则做了两个异常(exception):

  • 旧应用程序的通知以黑色显示
    背景;
  • 使用 MediaStyle 创建的通知可以是任何颜色。

  • 由于第二个异常(exception),这种限制看起来不合逻辑且不合理,这是您仍然想使用自定义颜色而不是谷歌推荐(或强制?)的唯一可能的借口。

    里面有什么
    让我们看看BaseStatusBar看看这个限制是如何施加的。唯一计算通知背景颜色的地方是applyColorsAndBackgrounds method .if 的第一个分支声明适用于遗留应用程序。到达这里的唯一方法是将应用程序的目标 SDK 设置在 Build.VERSION_CODES.LOLLIPOP 以下。 .在这种情况下,背景将变为黑色。
    我们对 entry.row.setTintColor 感兴趣陈述。要达到它,应该通过几项检查,包括 isMediaNotification method 中的一项。 .他们来了:
  • 通知必须包含常规 View 和大 View 。
  • 两个 View 中的顶级布局必须有 com.android.internal.R.id.status_bar_latest_event_content作为它的 ID。
  • 大布局必须包含一个带有 com.android.internal.R.id.media_actions 的小部件作为它的 ID。

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

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

    所以,最终的想法很简单:
  • 根据 Google 定义的内部布局构建通知(通过第二次检查)
  • 使用 removeAllViews 删除所有内容
  • 使用 addView 添加我们的自定义布局
  • 大 View 的特殊情况:添加由 Google 定义的布局,其中包含 media_actions在我们的自定义布局中隐藏 View (通过第三次检查)

  • 缺点:
  • 膨胀未使用的 View (膨胀后立即删除)
  • 复杂和更深的布局层次

  • 解决方案
    我们的自定义大 View 必须包含FrameLayoutandroid.R.id.empty作为它的 ID。实际上,这里可以使用任何 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在顶层操作大 View 的高度。搜索合适的here在 notification_template_xxx.xml 文件中。但不要忘记把 media_actions进入层次结构。

    关于android - Android Lollipop 中的通知背景是白色的。我怎样才能改变它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28169474/

    相关文章:

    ios - 锁屏ios上的本地通知

    android - 如何将参数传递给 Hilt 模块?

    javascript - 如何自动停止在后台运行的npm脚本

    java - 如果使用RelativeLayout则未设置背景图像

    iphone - 如何调用applicationDidEnterBackground中的函数?

    react-native - react native 本地通知

    android - RxJava - 捕捉消费者异常

    Android 在三星设备上保持屏幕开启

    android - 在 Android Studio 中全局设置 Android NDK

    ios - 移动背景在 Spritekit 上停止重复