Пользовательские макеты уведомлений и цвета текста - PullRequest
78 голосов
/ 01 февраля 2011

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

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

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

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

Ответы [ 11 ]

80 голосов
/ 08 февраля 2011

Решением является использование встроенных стилей. Стиль, который вам нужен, называется 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.

  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 Level 9) не было ни стилей, ни цветов, были только жестко заданные значения. Если вам по какой-то причине приходится поддерживать такие старые версии, см. Ответ от Gaks .

58 голосов
/ 06 сентября 2011

Решение от 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);
16 голосов
/ 06 января 2012

Вот решение для любой версии 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 / layout / 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-.Так что проблемы могут возникнуть с некоторыми редкими старыми кастомными прошивками.

13 голосов
/ 06 декабря 2011

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

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

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

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

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

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

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

2 голосов
/ 02 февраля 2011

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

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

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

1 голос
/ 25 августа 2018

Я использую это для рассматриваемого TextView:

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

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

1 голос
/ 21 февраля 2012

Я нашел очень простое решение, напрямую меняющее имя атрибута, предоставляемого 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>

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

1 голос
/ 06 февраля 2011

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

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

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

0 голосов
/ 13 мая 2019

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

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

    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;

    }
...