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


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

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

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

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

10 75

10 ответов:

решение от 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 ie. в 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);

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

вот решение для любой версии SDK, используя только ресурсы.

res / значения / стили.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"
    />
...

P. S: жестко закодированные значения используются для 2.2-. Таким образом, проблемы могут возникнуть с некоторыми редкими старыми пользовательскими прошивками.

Для 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-не работает. Просто попробуйте это с помощью эмулятора. Путь Гаков-единственный путь.

больше ресурсов: этой и этой не работают.

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

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

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

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

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

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

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

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

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

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

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

решение от @Malckom не помогло мне в Lolipop с темным фоном уведомлений из-за TextAppearance.Материал.Уведомление.Название - это системный жестко закодированный цвет. Решение от @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();
    }
}
// ...

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

    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;

    }