Diseños de notificación personalizados y colores de texto

Mi aplicación muestra algunas notificaciones y, dependiendo de las preferencias del usuario, puede usar un diseño personalizado en una notificación. Funciona bien, pero hay un pequeño problema: colores de texto . Stock Android y casi todos los skins del fabricante usan texto negro sobre un fondo claro para el texto de notificación, pero Samsung no: su menú desplegable de notificaciones tiene un fondo oscuro y el texto en el diseño de notificación predeterminado es blanco.

Esto causa un problema: las notificaciones que no usan diseños elegantes aparecen bien, pero la que usa un diseño personalizado es difícil de leer porque el texto es negro en lugar del blanco predeterminado. Incluso la documentación oficial solo establece un color #000 para una vista de TextView , por lo que no pude encontrar punteros allí.

Un usuario tuvo la amabilidad de tomar una captura de pantalla del problema:

Captura de pantalla

Entonces, ¿ cómo uso el color de texto de notificación predeterminado del dispositivo en mis diseños? Prefiero no comenzar a modificar dinámicamente el color del texto en función del modelo de teléfono, ya que requiere mucha actualización y las personas con ROM personalizadas pueden tener el problema, dependiendo de la máscara que estén usando.

La solución de Malcolm funciona bien con API> = 9. Aquí está la solución para una API más antigua:

El truco es crear el objeto de notificación estándar y luego recorrer el contenido predeterminado creado por Notification.setLatestEventInfo(...) . Cuando encuentre el TextView correcto, simplemente obtenga tv.getTextColors().getDefaultColor() .

Aquí está el código que extrae el color del texto predeterminado y el tamaño del texto (en píxeles de densidad escalada – 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; } } 

Llamar extractColors es decir. en onCreate () de su servicio. Luego, cuando está creando la notificación personalizada, el color y el tamaño de texto que desea se encuentran en notification_text_color y 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); 

La solución es usar estilos incorporados. El estilo que necesita se llama TextAppearance.StatusBar.EventContent en Android 2.3 y Android 4.x. En las notificaciones de material de Android 5.x, se usan varios otros estilos: TextAppearance.Material.Notification , TextAppearance.Material.Notification.Title y TextAppearance.Material.Notification.Line2 . Simplemente configure la apariencia del texto apropiado para la vista de texto, y obtendrá los colores necesarios.

Si está interesado en cómo he llegado a esta solución, aquí está mi rastro de migas de pan. Los extractos del código están tomados de Android 2.3.

  1. Cuando usa Notification y establece el texto usando medios incorporados, la siguiente línea crea el diseño:

     RemoteViews contentView = new RemoteViews(context.getPackageName(), com.android.internal.R.layout.status_bar_latest_event_content); 
  2. El diseño mencionado contiene la siguiente View que es responsable de ver el texto de notificación:

      
  3. Entonces, la conclusión es que el estilo necesario es TextAppearance.StatusBar.EventContent , cuya definición se ve así:

      

    Debe tener en cuenta que este estilo no hace referencia a ninguno de los colores incorporados, por lo que la forma más segura es aplicar este estilo en lugar de un color incorporado.

Una cosa más: antes de Android 2.3 (API Nivel 9), no había ni estilos ni colores, solo había valores codificados. Si por alguna razón tiene que admitir versiones antiguas, vea la respuesta de Gaks .

Aquí hay una solución para cualquier versión de SDK que use solo recursos.

res / values ​​/ styles.xml

      

res / values-v9 / styles.xml

      

res / layout / my_notification.xml

 ...   ... 

PD: los valores codificados se usan para 2.2-. Por lo tanto, pueden surgir problemas con algunos firmwares antiguos raros.

Para 2.3+ (De la documentación de Android ):

Use el estilo android:TextAppearance.StatusBar.EventContent.Title para el texto principal.

Use el estilo android:TextAppearance.StatusBar.EventContent para el texto secundario.

Para 2.2-, haz lo que Gaks sugirió en otra respuesta a este hilo.

Si quieres comstackr contra 2.2 y soportar 2.3+, y admitir toda la variedad de dispositivos que existen, la solución de Gaks es la única que conozco.

Por cierto, lo que Google sugirió sobre el uso del valor ?android:attr/textColorPrimary para 2.2-, no está funcionando. Solo inténtalo usando el emulador. El camino de Gaks es la única forma.

Más recursos: esto y esto no funcionan.

Debes usar los colores especificados en android.R.color

Por ejemplo: android.R.color.primary_text_light

Se supone que los desarrolladores de ROM personalizados y los diseñadores de la piel de Android deben actualizarlos para que los colores de su aplicación puedan estar en línea con el rest del sistema. Esto incluye asegurarse de que su texto se muestre correctamente en todo el sistema.

He encontrado una solución muy simple que cambia directamente el nombre del atributo proporcionado por Android.

Como puede ver en este tutorial: http://www.framentos.com/android-tutorial/2012/02/20/how-to-create-a-custom-notification-on-android/

Solo necesitas usar un atributo diferente:

 ?android:attr/textColorPrimaryInverse 

¡Espero que esto le pueda ayudar!

Lea estas instrucciones: http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Si configura el color de fondo para el contenedor LinearLayout, puede tener sus colores en la notificación de texto y el fondo.

Si la aplicación iniciadora define el color predeterminado para el texto de notificación, no podrá recuperarlo de la configuración predeterminada de Android a menos que el iniciador esté filtrando esta información.

Sin embargo, ¿ha intentado eliminar esta línea de android: textColor = “# 000” de su diseño para que pueda obtener automáticamente el color predeterminado?

Yo uso esto en el TextView en cuestión:

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

Me da texto blanco si el fondo es negro y negro si el fondo es blanco. Y funciona al menos desde API 19.

La solución de @Malckom no me ayudó en Lolipop con el fondo de notificación oscuro debido a TextAppearance.Material.Notification.Title es un sistema de color codificado. La solución de @grzaks sí, pero con algunos cambios dentro del proceso de creación de notificaciones:

 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(); } } // ... 

Sé que es una vieja pregunta, pero podría ayudar a otra persona; ) Lo hago en mi aplicación y funciona perfecto en algunas líneas:

  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; }