Пользовательские макеты уведомлений и цвета текста
Мое приложение показывает некоторые уведомления, и в зависимости от пользовательских настроек оно может использовать пользовательский макет в уведомлении. Работает хорошо, но есть небольшая проблема - цвета текста. В стандартном Android и почти всех скинах производителей используется черный текст на светлом фоне для текста уведомления, но Samsung этого не делает: их раскрывающийся список уведомлений имеет темный фон, а текст в макете уведомлений по умолчанию белый.
Таким образом, это вызывает проблему: уведомления, которые не используют какие-либо причудливые макеты, отображаются нормально, но тот, который использует пользовательский макет, трудно читается, потому что текст черный вместо белого по умолчанию. Даже официальная документация просто устанавливает #000
цвет для TextView
поэтому я не смог найти там указателей.
Пользователь был достаточно любезен, чтобы сделать скриншот проблемы:
Так как же использовать цвет текста уведомления по умолчанию с устройства в моих макетах? Я бы предпочел не начинать динамическое изменение цвета текста в зависимости от модели телефона, поскольку это требует большого обновления, и люди с пользовательскими ПЗУ могут по-прежнему сталкиваться с проблемой, в зависимости от используемой ими оболочки.
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
то есть. в 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.
Когда вы используете
Notification
и установить текст с помощью встроенных средств, следующая строка создает макет:RemoteViews contentView = new RemoteViews(context.getPackageName(), com.android.internal.R.layout.status_bar_latest_event_content);
Упомянутый макет содержит следующее
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" />
Таким образом, вывод заключается в том, что необходимый стиль
TextAppearance.StatusBar.EventContent
какое определение выглядит так:<style name="TextAppearance.StatusBar.EventContent"> <item name="android:textColor">#ff6b6b6b</item> </style>
Здесь вы должны заметить, что этот стиль на самом деле не ссылается ни на один из встроенных цветов, поэтому самый безопасный способ - применить этот стиль вместо какого-то встроенного цвета.
Еще одна вещь: до Android 2.3 (API Level 9) не было ни стилей, ни цветов, были только жестко заданные значения. Если вам по какой-то причине приходится поддерживать такие старые версии, см. Ответ Гакса.
Вот решение для любой версии SDK, используя только ресурсы.
RES / значения /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 / значения-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>
разреш / макет / 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-. Так что проблемы могут возникнуть с некоторыми редкими старыми кастомными прошивками.
Для 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- не работает. Просто попробуйте с помощью эмулятора. Путь Гакса - единственный путь.
Я использую это на TextView в вопросе:
style="@style/TextAppearance.Compat.Notification.Title"
Это дает мне белый текст, если фон черный и черный текст, если фон белый. И это работает, по крайней мере, еще до API 19.
Вы должны использовать цвета, указанные в android.R.color
Например: android.R.color.primary_text_light
Разработчики пользовательских ПЗУ и дизайнеры скинов 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 Если вы установите цвет фона для контейнера LinearLayout, тогда вы можете иметь свои цвета в уведомлении для текста и фон.
Если цвет по умолчанию для текста уведомления определяется приложением запуска, вы не сможете получить его из настроек по умолчанию для Android, пока средство запуска не поделится этой информацией.
Однако пытались ли вы удалить эту строку android:textColor="#000" из макета, чтобы он мог автоматически получать цвет по умолчанию?
Я знаю, что это старый вопрос, но он может помочь кому-то еще;) Я делаю это в своем приложении, и это отлично работает в несколько строк:
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;
}
Решение от @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();
}
}
// ...
Вот что помогло мне решить эту ошибку. Добавьте следующее в 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>
В вашем наборе расширяемых или свернутых макетов
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
файл в простом цветовом файле, а также в цветном файле ночного режима