Пользовательские макеты уведомлений и цвета текста

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

Таким образом, это вызывает проблему: уведомления, которые не используют какие-либо причудливые макеты, выглядят хорошо, но тот, который использует настраиваемый макет, трудно читать, потому что текст черный, а не белый по умолчанию. Даже официальная документация просто устанавливает цвет #000 для TextView, поэтому я не мог найти там никаких указателей.

Пользователь был достаточно любезен, чтобы снять снимок экрана:

Screenshot

Итак как использовать цвет текста уведомлений по умолчанию с устройства в моих макетах? Я бы предпочел не начинать динамически изменять цвет текста на основе модели телефона, поскольку для этого требуется много обновлений, и люди с пользовательским ПЗУ могут все еще получить проблему, в зависимости от используемого ими скина.

Ответ 1

Решение 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);

Ответ 2

Решение состоит в использовании встроенных стилей. Нужный стиль называется TextAppearance.StatusBar.EventContent в Android 2.3 и Android 4.x. В уведомлениях материала для Android 5.x используются несколько других стилей: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title и TextAppearance.Material.Notification.Line2. Просто установите соответствующий текст для текстового вида, и вы получите необходимые цвета.

Если вам интересно, как я пришел к этому решению, вот мой след сухарей. Выдержки из кода взяты из Android 2.3.

  • Когда вы используете Notification и устанавливаете текст с помощью встроенных средств, следующая строка создает макет:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.android.internal.R.layout.status_bar_latest_event_content);
    
  • Указанный макет содержит следующее 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"
        />
    
  • Итак, вывод состоит в том, что нужный стиль TextAppearance.StatusBar.EventContent, определение которого выглядит следующим образом:

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

    Здесь вы должны заметить, что этот стиль фактически не ссылается ни на один из встроенных цветов, поэтому самый безопасный способ - применить этот стиль вместо встроенного цвета.

Еще одна вещь: до Android 2.3 (уровень API 9) не было ни стилей, ни цветов, были только жестко закодированные значения. Если вам почему-то приходится поддерживать такие старые версии, см. Ответ от Gaks.

Ответ 3

Вот решение для любой версии SDK с использованием только ресурсов.

RES/значения/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/значения-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>

Рез/макет/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"
    />
...

P.S: Твердые кодированные значения используются для 2.2-. Таким образом, проблемы могут возникать при использовании некоторых редких старых прошивок.

Ответ 4

Для 2.3+ (From Документация для Android):

Используйте стиль android:TextAppearance.StatusBar.EventContent.Title для основного текста.

Используйте стиль android:TextAppearance.StatusBar.EventContent для вторичного текста.

Для 2.2- сделайте то, что предложил Гакс в другом ответе на этот поток.

Если вы хотите скомпилировать с 2.2 и поддерживать 2.3+ и поддерживать все различные устройства, решение Gaks - это единственное, что я знаю.

Кстати, что Google предложил использовать значение ?android:attr/textColorPrimary для 2.2-, не работает. Просто попробуйте использовать эмулятор. Способ Гакса - единственный способ.

Дополнительные ресурсы: Это и this do не работает.

Ответ 5

Вы должны использовать цвета, указанные в android.R.color

Например: android.R.color.primary_text_light

Разработчики пользовательских дисков и разработчики скинов для Android должны обновлять их, поэтому ваши цвета приложений могут соответствовать остальной части системы. Это включает в себя обеспечение правильного отображения текста во всей системе.

Ответ 6

Посмотрите на следующие инструкции: http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Если вы настроили свой фоновый цвет для контейнера LinearLayout, вы можете получить свои цвета в уведомлении для текста и фона.

Если цвет по умолчанию для текста уведомления определяется приложением запуска, вы не можете получить его из настроек по умолчанию для Android, если только пусковая установка не обменивает эту информацию.

Однако, попытаетесь ли вы удалить эту строку android: textColor = "# 000" из вашего макета, чтобы он мог автоматически получать цвет по умолчанию?

Ответ 7

Я нашел очень простое решение, напрямую изменяющее имя атрибута, предоставленного Android.

Как вы можете видеть в этом уроке: http://www.framentos.com/android-tutorial/2012/02/20/how-to-create-a-custom-notification-on-android/

Вам нужно использовать только другой атрибут:

<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>

Надеюсь, это поможет вам!

Ответ 8

Я использую это на TextView в вопросе:

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

Это дает мне белый текст, если фон черный и черный текст, если фон белый. И это работает, по крайней мере, еще до API 19.

Ответ 9

Решение от @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();
    }
}
// ...

Ответ 10

Я знаю, что это старый вопрос, но он может помочь кому-то другому; ) Я делаю это в своем приложении и прекрасно работает в нескольких строках:

    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;

    }

Ответ 11

Вот что помогло мне решить эту ошибку. Добавьте следующее в 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>