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

82

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

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

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

Скриншот

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

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

A-IV
источник
уверен, что цвет текста нужен? родитель уже устанавливает это, нет?
разработчик 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>
Inder
источник
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файле в простом цветовом файле, так и в цветном файле ночного режима.

АДИТЬЯ ЙОГЕШБХАЙ ДАЛВАДИ
источник