Android Lollipop中的通知背景为白色.我该怎么改变它?

Man*_*our 13 notifications android background transparent android-5.0-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>
Run Code Online (Sandbox Code Playgroud)

我在棒棒糖中的通知显示如下: 棒棒糖的通知方式

如何将通知背景设置为暗或透明,就像以前的Android版本一样?

Krz*_*cki 7

最后,如果您想遵循官方材料设计规范

始终将样式资源用于自定义通知的文本

并使用通知的自定义布局,您可能会考虑不覆盖默认背景,但由于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>
Run Code Online (Sandbox Code Playgroud)

值/ 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>
Run Code Online (Sandbox Code Playgroud)


Sta*_*lav 6

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

原因简析
没有合法的方法为自定义通知设置背景颜色.根据Material Design,Google决定通知必须是白色或浅灰色,具体取决于其优先级.但是,Google也对此规则提出了两个例外:

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

由于第二个例外,这种限制看起来不合逻辑和不合理,这是唯一可能的理由,为什么你仍然想要使用自定义颜色而不是谷歌推荐(或强制?)的颜色.

内部的内容
让我们看看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_actionsID 的小部件.

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

但是,谷歌为他们的需求添加了这些addViewremoveAllViews方法RemoteViews(它们在MediaStyle通知中使用)并忘记将它们设为私有.

所以,最后的想法很简单:

  • 根据Google定义的内部布局构建通知(通过第二次检查)
  • 删除一切 removeAllViews
  • 添加我们的自定义布局 addView
  • 大视图的特殊情况:添加由Google定义的布局,其中包含media_actions自定义布局内的隐形视图(通过第3次检查)

缺点:

  • 膨胀未使用的视图(在充气后立即移除)
  • 复杂而深入的布局层次

解决方案:
我们的定制大视图必须包含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
Run Code Online (Sandbox Code Playgroud)

可以使用另一种布局而不是notification_template_material_big_media_narrow顶层来操纵大视图的高度.搜索一个合适的位置 notification_template_xxx.xml文件中.但是不要忘记media_actions进入等级制度.