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


82

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

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

Пользователь любезно сделал снимок экрана с проблемой:

Скриншот

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


10
изображение больше не доступно
Амир Уваль

Перезагрузите образ, пожалуйста, если есть возможность.
Maciej Gol

Ответы:


63

Решение Малкольма отлично работает с 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 разных цвета - для заголовка и для основного содержимого. Я хочу получить оба, но с помощью этого метода смог получить только цвет заголовка - итерация, похоже, находит только одно текстовое поле. Есть идеи?
Hermit

1
Я вижу то же, что и @Raw, только один TextView. Я заменил "Utest" другим советом по поиску (и с другой строкой). Он находит только один TextView и соответствует COLOR_SEARCH_RECURSE_TIP. Есть указатели? Спасибо.
ciscogambo

6
Причина, по которой он находит только одну, - это ошибка в "return recurseGroup ((ViewGroup) gp.getChildAt (i));" - метод должен возвращать только в том случае, если внутренний "recurseGroup" вернул true. Это должно быть: «if (recurseGroup ((ViewGroup) gp.getChildAt (i))) return true;». Спасибо за решение - отличное нестандартное мышление.
AlikElzin-kilaka 06

9
Спасибо за этот ответ, это очень помогло. Для всех, кого это интересует, я собрал быстрый класс, который можно использовать, чтобы получить как заголовок, так и цвет / размер текста на основе ответа Gaks. Его можно найти здесь: pastebin.com/sk08QGxs
NuSkooler

3
Остерегайтесь этого предложения , потому что это не так (проверено в Galaxy Ace с уровнем 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.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 .


Не думаю, что понимаю этот ответ. В последнем предложении говорится, что для этого нельзя использовать указатель цвета. Какой цвет использовать в этом случае?
Стив Помрой,

Тем не менее, я заметил в журнале изменений 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

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


уверен, что цвет текста нужен? родитель уже устанавливает это, нет?
разработчик Android

13

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

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

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

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

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

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

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


5
Ваши инструкции 2.3+ не работали для Android 5. Он выводил белый текст на белом фоне.
Сэм,

6

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

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

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


2

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

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

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


Какой цвет я должен использовать android.R.color? Все цвета текста имеют как «темные», так и «светлые» варианты.
Veeti 02

1
У меня нет устройства с настраиваемой темой, поэтому я не могу проверить, какое из них использовать. Я бы сказал, попробуйте оба и посмотрите, какой из них вам подходит.
Остин Махони

1

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

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

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


1
Удаление цвета текста не помогает - цвет по умолчанию не соответствует цветам уведомлений.
Veeti

Вы пытались изменить фон? Я считаю, что это серьезная проблема, и хорошо, что вы ее подняли. Вы пробовали форум / группы разработчиков Google?
Lumis

1

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

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

    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" />

И ваш цвет текстового представления определяет черный и белый, как в Resource/colorфайле в простом цветовом файле, так и в цветном файле ночного режима.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.