Спеціальні макети сповіщень та кольори тексту


82

У моїй програмі відображаються деякі сповіщення, і залежно від уподобань користувача він може використовувати власне розміщення в сповіщенні. Це працює добре, але є невелика проблема - кольори тексту . Фондова платформа Android та майже всі обробники виробників використовують чорний текст на світлому фоні для тексту сповіщень, але Samsung цього не робить: їх розкривне сповіщення має темний фон, а текст у розкладці сповіщень за замовчуванням білий.

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

Користувач виявився досить ласкавим, щоб зробити скріншот проблеми:

Знімок екрана

Отже, як я використовую колір тексту сповіщення за замовчуванням із пристрою у своїх макетах? Я волів би не починати динамічно змінювати колір тексту на основі моделі телефону, оскільки для цього потрібно багато оновлювати, і люди зі спеціальними ПЗУ все одно можуть отримати проблему, залежно від шкіри, яку вони використовують.


10
зображення більше не доступне
— Amir Uval

Перезавантажте зображення, якщо це можливо, будь ласка.
— Maciej Gol

Відповіді:


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 чудова відповідь. Працює добре. Я помітив, що існує два різні кольори за замовчуванням - для заголовка та для основного вмісту. Я хочу отримати обидва, але мені вдалося отримати колір заголовка лише за допомогою цього методу - ітерація, здається, знаходить лише 1 текстове поле. Будь-які ідеї?
— Відлюдник

1
Я бачу те саме, що @Raw, лише один TextView. Я замінив "Utest" на іншу підказку для пошуку (і на інший рядок). Він знаходить лише один TextView, і він відповідає COLOR_SEARCH_RECURSE_TIP. Будь-які вказівники? Дякую.
— ciscogambo

6
Причиною того, що він знаходить лише одну, є помилка у "return repeatseGroup ((ViewGroup) gp.getChildAt (i));" - метод повинен повертатися, лише якщо внутрішня "repeatseGroup" повертає true. Це має бути: "if (repeatseGroup ((ViewGroup) gp.getChildAt (i))) return true;". Дякую за рішення - чудове нестандартне мислення.
— AlikElzin-kilaka

9
Дякую за цю відповідь, це було дуже корисно. Для всіх, хто цікавиться, я зібрав швидкий клас, який можна опустити, щоб отримати як заголовок, так і колір / розмір тексту на основі відповіді Гакса. Його можна знайти тут: 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 9) не було ні стилів, ні кольорів, були лише жорстко закодовані значення. Якщо вам з якихось причин доведеться підтримувати такі старі версії, див. Відповідь Гакса .


Я не думаю, що розумію цю відповідь. В останньому реченні зазначено, що для цього не існує посилання на колір. Який колір слід використовувати в цьому випадку?
— Steve Pomeroy

Тим не менш, я помітив в журналі змін Android, що лише починаючи з рівня 9 API, android: textAppearance = "@ androidstyle / TextAppearance.StatusBar.EventContent" був оприлюднений. До того це було приховано.
— Steve Pomeroy

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+, і підтримувати всі різноманітні пристрої, єдине, що я знаю, - рішення Гакса.

До речі, те, що 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.