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

81

Mi aplicación muestra algunas notificaciones y, según las preferencias del usuario, puede usar un diseño personalizado en una notificación. Funciona bien, pero hay un pequeño problema: los colores del texto . Stock de Android y casi todas las máscaras de los fabricantes 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.

Entonces, esto causa un problema: las notificaciones que no usan ningún diseño elegante se muestran 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 #000color para a TextView, por lo que no pude encontrar ningún puntero allí.

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

Captura de pantalla

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

Veeti
fuente
9
imagen ya no disponible
Amir Uval
Vuelva a cargar la imagen, si es posible, por favor.
Maciej Gol

Respuestas:

63

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

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

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

Llame extractColorsie. en onCreate () de su servicio. Luego, cuando esté creando la notificación personalizada, el color y el tamaño del texto que desea están en notification_text_colory 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);
grzaks
fuente
1
+1 gran respuesta. Funciona bien. Me di cuenta de que parece haber 2 colores predeterminados diferentes: para el título y para el contenido principal. Quiero buscar ambos, pero solo he podido obtener el color del título usando este método; la iteración parece encontrar solo 1 cuadro de texto. ¿Algunas ideas?
Ermitaño
1
Veo lo mismo que @Raw, solo un TextView. Reemplacé "Utest" con otro consejo de búsqueda (y con una cadena diferente). Solo encuentra un TextView y coincide con COLOR_SEARCH_RECURSE_TIP. ¿Algún consejo? Gracias.
Ciscogambo
6
La razón por la que solo encuentra uno es un error en "return recurseGroup ((ViewGroup) gp.getChildAt (i));" - el método debe regresar solo si el "recurseGroup" interno devolvió verdadero. Debería ser: "if (recurseGroup ((ViewGroup) gp.getChildAt (i))) return true;". Gracias por la solución: excelente pensamiento innovador.
AlikElzin-kilaka
9
Gracias por esta respuesta, fue muy, muy útil. Para cualquier persona interesada, preparé una clase rápida que se puede ingresar para buscar tanto el título como el color / tamaño del texto según la respuesta de Gaks. Se puede encontrar aquí: pastebin.com/sk08QGxs
NuSkooler
3
Cuidado con esta frase, porque es no es verdad (probado en un Galaxy Ace con la API de nivel 10): Solution by Malcolm works fine with API>=9. Ya sabes, Android y los fabricantes son algo complicado. Utilice esta solución para cada plataforma.
cprcrack
83

La solución es utilizar estilos integrados. El estilo que necesita se llama TextAppearance.StatusBar.EventContenten Android 2.3 y Android 4.x. En Android 5.x notificaciones materiales utilizan varios otros estilos: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title, y TextAppearance.Material.Notification.Line2. Simplemente configure la apariencia de texto apropiada 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 se tomaron de Android 2.3.

  1. Cuando usa Notificationy configura el texto usando medios integrados, 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 lo siguiente Viewque es responsable de ver el texto de notificación:

    <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. Entonces, la conclusión es que el estilo necesario es TextAppearance.StatusBar.EventContent, cuya definición se ve así:

    <style name="TextAppearance.StatusBar.EventContent">
        <item name="android:textColor">#ff6b6b6b</item>
    </style>
    

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

Una cosa más: antes de Android 2.3 (API nivel 9), no había estilos ni colores, solo había valores codificados. Si tiene que admitir versiones tan antiguas por algún motivo, consulte la respuesta de Gaks .

Malcolm
fuente
No creo que entiendo esta respuesta. La oración final establece que no hay una referencia de color que pueda usarse para esto. ¿Qué color se debe utilizar en este caso?
Steve Pomeroy
Dicho esto, noté en el registro de cambios de Android que solo a partir del nivel de API 9, el android: textAppearance = "@ androidstyle / TextAppearance.StatusBar.EventContent" se hizo público. Antes de eso, estaba oculto.
Steve Pomeroy
1
No estaba oculto antes de Android 2.3, simplemente no existía. En ese entonces había un valor codificado en el diseño, y si el proveedor del dispositivo decidía cambiarlo, no podría hacer nada al respecto. No había colores o estilos a través de los cuales pudiera acceder a este valor. En este momento todavía no tiene colores, pero tiene un estilo, que puede aplicar para obtener este color de texto específico. ¿Tener sentido? :)
Malcolm
3
¿Qué estilo local? El estilo en mi respuesta se toma directamente de la fuente de Android. Lo aplica como cualquier otro estilo integrado ( style="@android:style/TextAppearance.StatusBar.EventContent") y obtiene el color necesario para el texto. Será #ff6b6b6ben el caso de Android vainilla, o cualquier color que haya establecido el proveedor del dispositivo.
Malcolm
4
Solo para que otros sepan, esto no funciona en Android 6+
iGoDa
17

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

res / valores / estilos.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 / valores-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: Los valores codificados de forma rígida se utilizan para 2.2-. Por lo tanto, pueden ocurrir problemas con algunos firmwares personalizados antiguos raros.

A-IV
fuente
¿Seguro que se necesita el color del texto? el padre ya lo configura, ¿no?
desarrollador de Android
13

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

Utilice el estilo android:TextAppearance.StatusBar.EventContent.Titlepara el texto principal.

Utilice el estilo android:TextAppearance.StatusBar.EventContentpara el texto secundario.

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

Si desea compilar contra 2.2 y admitir 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/textColorPrimaryde 2.2-, no está funcionando. Pruébalo usando el emulador. El camino de Gaks es el único camino.

Más recursos: esto y esto no funcionan.

AlikElzin-kilaka
fuente
5
Tus instrucciones 2.3+ no funcionaron para Android 5. Produjo texto blanco sobre un fondo blanco.
Sam
5

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 texto negro si el fondo es blanco. Y funciona al menos desde API 19.

Gavin Wright
fuente
2

Debe utilizar 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 máscaras de Android deben actualizarlos para que los colores de su aplicación puedan estar en línea con el resto del sistema. Esto incluye asegurarse de que su texto se muestre correctamente en todo el sistema.

Austyn Mahoney
fuente
¿De qué color se supone que debo usar android.R.color? Todos los colores del texto tienen variaciones tanto "oscuras" como "claras".
Veeti
1
No tengo un dispositivo con un tema personalizado, así que no puedo probar cuál usar. Yo diría que pruebe ambos y vea cuál funciona para usted.
Austyn Mahoney
1

Mira estas instrucciones: http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Si configuras tu color de fondo para el contenedor LinearLayout, entonces puedes tener tus colores en notificaciones para texto y el fondo.

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

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

Lumis
fuente
1
Eliminar el color del texto no ayuda; el valor predeterminado no coincide con los colores de notificación.
Veeti
¿Intentaste cambiar el fondo? Creo que este es un problema grave y es bueno que lo hayas mencionado. ¿Has probado los foros / grupos de desarrolladores de Google?
Lumis
1

Sé que es una pregunta antigua, pero podría ayudar a otra persona; ) Hago esto 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;

    }
Samet
fuente
0

La solución de @Malckom no me ayudó en Lolipop con un fondo de notificación oscuro debido a TextAppearance.Material.Notification.Title es un color codificado del sistema. La solución de @grzaks lo hizo, 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();
    }
}
// ...
Yurii Solopov
fuente
0

Esto es lo que funcionó para mí para resolver este error. Agregue lo siguiente a 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>
inder
fuente
0

En su diseño expandible o contraído, establezca android:backgroundcomo un "@android:color/transparent"porque esto automáticamente toma el color del tema de notificación de su dispositivo y lo establece como fondo

<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" />

Y el color de su vista de texto define el blanco y negro como en un Resource/colorarchivo en un archivo de color simple y como un archivo de color en modo nocturno

ADITYA YOGESHBHAI DALWADI
fuente