自定义通知布局和文本颜色


81

我的应用程序显示了一些通知,根据用户的喜好,它可能会在通知中使用自定义布局。它运作良好,但有一个小问题-文字颜色。普通的Android设备和几乎所有制造商的外观都在浅色背景上使用黑色文本作为通知文本,但三星却没有:其通知下拉菜单具有深色背景,默认通知布局中的文本为白色。

因此,这会导致一个问题:不使用任何精美布局的通知显示得很好,但是使用自定义布局的通知却很难阅读,因为文本是黑色而不是默认的白色。甚至官方文档也只是为设置了#000颜色TextView,所以我在那里找不到任何指针。

用户很友善地拍摄了该问题的屏幕截图:

屏幕截图

那么,如何在布局中使用设备的默认通知文本颜色?我宁愿不开始根据电话型号动态更改文本颜色,因为这需要进行大量更新,并且具有自定义ROM的人可能仍然会遇到问题,具体取决于他们所使用的皮肤。


9
图片不再可用
Amir Uval

请重新上传图片。
Maciej Gol

Answers:


63

Malcolm的解决方案在API> = 9时可以正常工作。这是旧版API的解决方案:

技巧是创建标准通知对象,然后遍历由contentView创建的默认通知对象Notification.setLatestEventInfo(...)。找到正确的TextView后,只需获取tv.getTextColors().getDefaultColor()

这是提取默认文本颜色和文本大小(以缩放的密度像素为单位-sp)的代码。

private Integer notification_text_color = null;
private float notification_text_size = 11;
private final String COLOR_SEARCH_RECURSE_TIP = "SOME_SAMPLE_TEXT";

private boolean recurseGroup(ViewGroup gp)
{
    final int count = gp.getChildCount();
    for (int i = 0; i < count; ++i)
    {
        if (gp.getChildAt(i) instanceof TextView)
        {
            final TextView text = (TextView) gp.getChildAt(i);
            final String szText = text.getText().toString();
            if (COLOR_SEARCH_RECURSE_TIP.equals(szText))
            {
                notification_text_color = text.getTextColors().getDefaultColor();
                notification_text_size = text.getTextSize();
                DisplayMetrics metrics = new DisplayMetrics();
                WindowManager systemWM = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
                systemWM.getDefaultDisplay().getMetrics(metrics);
                notification_text_size /= metrics.scaledDensity;
                return true;
            }
        }
        else if (gp.getChildAt(i) instanceof ViewGroup)
            return recurseGroup((ViewGroup) gp.getChildAt(i));
    }
    return false;
}

private void extractColors()
{
    if (notification_text_color != null)
        return;

    try
    {
        Notification ntf = new Notification();
        ntf.setLatestEventInfo(this, COLOR_SEARCH_RECURSE_TIP, "Utest", null);
        LinearLayout group = new LinearLayout(this);
        ViewGroup event = (ViewGroup) ntf.contentView.apply(this, group);
        recurseGroup(event);
        group.removeAllViews();
    }
    catch (Exception e)
    {
        notification_text_color = android.R.color.black;
    }
}

致电extractColors即。在服务的onCreate()中。然后,当您创建自定义通知时,所需的颜色和文本大小位于notification_text_color和中notification_text_size

Notification notification = new Notification();
RemoteViews notification_view = new RemoteViews(getPackageName(), R.layout.notification);       
notification_view.setTextColor(R.id.label, notification_text_color);
notification_view.setFloat(R.id.label, "setTextSize", notification_text_size);

1
+1好答案。效果很好。我注意到似乎有2种不同的默认颜色-标题和主要内容。我想同时获取两者,但只能使用此方法获取标题颜色-迭代似乎只能找到1个文本框。有任何想法吗?
隐士

1
我看到的与@Raw相同,只有一个TextView。我用另一个搜索提示(和另一个字符串)替换了“ Utest”。它仅找到一个TextView,并且与COLOR_SEARCH_RECURSE_TIP匹配。有指针吗?谢谢。
ciscogambo11年

6
它只能找到一个的原因是“ return recurseGroup((ViewGroup)gp.getChildAt(i));”中的错误。-仅当内部“ recurseGroup”返回true时,该方法才应返回。它应该是:“如果(recurseGroup((ViewGroup)gp.getChildAt(i)))返回true;”。感谢您的解决方案-出色的创新思维。
2011年

9
感谢您的回答,这非常有帮助。对于感兴趣的任何人,我都提供了一个快速的课堂,然后可以根据Gaks的答案直接进行课堂学习,以获取标题和文本的颜色/大小。可以在这里找到:pastebin.com/sk08QGxs
NuSkooler 2012年

3
当心这句话,因为这是不正确的(在银河王牌测试与API等级10): Solution by Malcolm works fine with API>=9。您知道,Android和制造商是一件棘手的事情。将此解决方案用于每个平台。
cprcrack

83

解决方案是使用内置样式。您需要的样式TextAppearance.StatusBar.EventContent在Android 2.3和Android 4.x中被称为。在Android的5.x的资料的通知使用其他几种风格:TextAppearance.Material.NotificationTextAppearance.Material.Notification.Title,和TextAppearance.Material.Notification.Line2。只需为文本视图设置适当的文本外观,您将获得必要的颜色。

如果您对我如何达到此解决方案感兴趣,这是我的痕迹。代码摘录取自Android 2.3。

  1. 当您使用Notification内置方式使用和设置文本时,以下行将创建布局:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.android.internal.R.layout.status_bar_latest_event_content);
    
  2. 提到的布局包含以下内容View,这些内容负责查看通知文本:

    <TextView android:id="@+id/text"
        android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:fadingEdge="horizontal"
        android:paddingLeft="4dp"
        />
    
  3. 因此,结论是所需的样式为TextAppearance.StatusBar.EventContent,其定义如下所示:

    <style name="TextAppearance.StatusBar.EventContent">
        <item name="android:textColor">#ff6b6b6b</item>
    </style>
    

    您应该在此处注意,此样式实际上并未引用任何内置颜色,因此最安全的方法是应用此样式而不是某些内置颜色。

还有一件事:在Android 2.3(API级别9)之前,既没有样式,也没有颜色,只有硬编码的值。如果由于某种原因您不得不支持此类旧版本,请参见Gaks答案


我想我不明白这个答案。最后一句话指出,没有可用于此目的的颜色参考。在这种情况下应使用什么颜色?
史蒂夫·波默罗伊

就是说,我在Android的变更日志中注意到,仅从API级别9开始,android:textAppearance =“ @ androidstyle / TextAppearance.StatusBar.EventContent”才公开。在此之前,它是隐藏的。
史蒂夫·波默罗伊

1
它在Android 2.3之前并未隐藏,只是根本不存在。那时,布局中有一个硬编码的值,如果设备供应商决定更改它,那么您将无能为力。没有颜色或样式可以通过它访问此值。现在,您仍然没有颜色,但是有一种样式,可以应用该样式来获得此特定的文本颜色。有道理?:)
马尔科姆

3
什么地方风格?我回答的样式直接取自Android来源。您可以将其应用为任何其他内置样式(style="@android:style/TextAppearance.StatusBar.EventContent"),并获得文本所需的颜色。将会是#ff6b6b6b香草Android,或者设备供应商在那里设置的任何颜色。
马尔科姆

4
只是让其他人知道,这不适用于Android 6+
iGoDa 2015年

17

这是仅使用资源的任何SDK版本的解决方案。

res / values / styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="NotificationTitle">
      <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
      <item name="android:textStyle">bold</item>
    </style>
    <style name="NotificationText">
      <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
    </style>
</resources>

res / values-v9 / styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" />
    <style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" />
</resources>

RES /布局/my_notification.xml

...
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="title"
    style="@style/NotificationTitle"
    />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="text"
    style="@style/NotificationText"
    />
...

PS:硬编码值用于2.2-。因此,某些稀有的旧定制固件可能会出现问题。


确定需要文本颜色吗?父母已经设置好了,不是吗?
Android开发人员

13

对于2.3及更高版本(来自Android文档):

使用样式android:TextAppearance.StatusBar.EventContent.Title作为主要文字。

使用样式android:TextAppearance.StatusBar.EventContent作为辅助文本。

对于2.2-,请执行Gaks在对该线程的另一个答案中建议的操作

如果您想针对2.2进行编译并支持2.3+,并支持其中的所有各种设备,那么我想知道Gaks的解决方案。

顺便说一句,Google关于使用该值的建议 ?android:attr/textColorPrimary2.2-,但不能正常工作。只需使用仿真器尝试即可。盖克斯的方法是唯一的方法。

更多资源:不工作。


5
您的2.3+指令不适用于Android5。它在白色背景上产生白色文本。
山姆

5

我在有问题的TextView上使用它:

style="@style/TextAppearance.Compat.Notification.Title"

如果背景是黑色,它会给我白色文本,如果背景是白色,则会给我黑色文本。而且它至少可以追溯到API 19。


2

您应该使用中指定的颜色 android.R.color

例如: android.R.color.primary_text_light

定制ROM开发人员和Android皮肤设计人员应该更新这些内容,以便您应用的颜色可以与系统其他部分保持一致。这包括确保您的文本在整个系统中正确显示。


我应该使用什么颜色android.R.color?所有文本颜色都有“深色”和“浅色”两种变化。
Veeti

1
我没有配备自定义主题的设备,因此我无法真正测试要使用的设备。我想尝试一下,看看哪一种适合您。
Austyn Mahoney 2011年

1

请查看以下说明:http : //developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView 如果您为LinearLayout容器设置了背景颜色,则可以在文本通知中使用颜色的背景。

如果启动器应用程序定义了通知文本的默认颜色,则除非启动器共享了此信息,否则您无法从android默认设置中检索它。

但是,您是否尝试从布局中删除此行android:textColor =“#000”,使其可以自动获得默认颜色?


1
删除文本颜色无济于事-默认值与通知颜色不匹配。
Veeti 2011年

您是否尝试过更改背景?我认为这是一个严重的问题,建议您提出。您是否尝试过Google开发者论坛/论坛?
Lumis


1

我知道这是一个老问题,但是它可以帮助别人; )我在我的应用程序中执行此操作,并且在以下几行中效果很好:

    RemoteViews notificationView = new RemoteViews(context.getPackageName(), R.layout.notification_layout);

    if (SDK >= LOLLIPOP) {

            TextView textView = new TextView(context);
            textView.setTextAppearance(context, android.R.style.TextAppearance_Material_Notification_Title);

            notificationView.setTextColor(R.id.title, textView.getCurrentTextColor());
            notificationView.setFloat(R.id.title, "setTextSize", textView.getTextSize());

            textView.setTextAppearance(context,android.R.style.TextAppearance_Material_Notification_Line2);

            notificationView.setTextColor(R.id.contentText,textView.getCurrentTextColor());
            notificationView.setFloat(R.id.contentText,"setTextSize",textView.getTextSize());

            textView = null;

    }

0

@Malckom的解决方案在Lolipop的深色通知背景中对我没有帮助,因为TextAppearance.Material.Notification.Title是系统硬编码的颜色。@grzaks提供了解决方案,但是在通知创建过程中进行了一些更改:

NotificationCompat.Builder mBuilder =
    new NotificationCompat.Builder(this)
                          .setContentTitle(NOTIFICATION_TITLE_TIP)
                          .setContentText(NOTIFICATION_TEXT_TIP);
Notification ntf = mBuilder.build();
// ...
if (NOTIFICATION_TEXT_TIP.equals(szText)) {
    notification_text_color = text.getTextColors().getDefaultColor();
} else {
    if (NOTIFICATION_TITLE_TIP.equals(szText)) {
        notification_title_color = text.getTextColors().getDefaultColor();
    }
}
// ...

0

这是我解决此错误的方法。将以下内容添加到styles.xml

    <style name="TextAppearance">
    </style>
    <style name="TextAppearance.StatusBar">
    </style>
    <style name="TextAppearance.StatusBar.EventContent">
        <item name="android:textColor">#ff6b6b6b</item>
    </style>
    <style name="TextAppearance.StatusBar.EventContent.Info">
        <item name="android:textColor">#ff6b6b6b</item>
    </style>

0

在您的展开式或折叠式布局中,将其设置 android:background为,"@android:color/transparent"因为这会自动采用设备通知主题的颜色并将其设置为背景

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_margin="0dp"
android:background="@android:color/transparent"
android:orientation="vertical">
          <TextView

            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/colorSecondary"
            android:textStyle="bold" />

并且您的textview颜色Resource/color在简单颜色文件以及夜间模式颜色文件中的文件中定义黑白

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.