Пользовательские макеты уведомлений и цвета текста
Мои приложения показывает некоторые уведомления, и в зависимости от предпочтений пользователя, он может использовать пользовательский макет в уведомлении. Он работает хорошо, но есть небольшая проблема -- цвета текста. Фондовый Android и почти все скины производителя используют черный текст на светлом фоне для текста уведомления, но Samsung этого не делает: их уведомление pulldown имеет темный фон, а текст в макете уведомлений по умолчанию белый.
Так что это вызывает проблему: уведомления, которые не используют никаких причудливых макетов, отображаются нормально, но тот, который использует пользовательский макет, трудно прочитать, потому что текст черный, а не белый по умолчанию. Даже официальная документация просто задает #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
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.
при использовании
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 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; }