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


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.