web-dev-qa-db-fra.com

Dispositions de notification et couleurs de texte personnalisées

Mon application affiche certaines notifications et, selon les préférences de l'utilisateur, elle peut utiliser une mise en page personnalisée dans une notification. Cela fonctionne bien, mais il y a un petit problème - couleurs de texte . Stock Android et presque tous les skins de fabricants utilisent du texte noir sur un fond clair pour le texte de notification, mais Samsung ne le fait pas: leur menu déroulant de notification a un fond sombre et le texte dans la disposition de notification par défaut est blanc .

Cela pose donc un problème: les notifications qui n'utilisent aucune mise en page fantaisie s'affichent bien, mais celle qui utilise une mise en page personnalisée est difficile à lire car le texte est noir au lieu du blanc par défaut. Même le documentation officielle définit juste un #000 couleur pour un TextView, donc je n'ai trouvé aucun pointeur là-bas.

Un utilisateur a eu la gentillesse de prendre une capture d'écran du problème:

Screenshot

Alors comment utiliser la couleur de texte de notification par défaut de l'appareil dans mes mises en page? Je préfère ne pas commencer à modifier dynamiquement la couleur du texte en fonction du modèle de téléphone, car cela nécessite beaucoup de mises à jour et les personnes possédant des ROM personnalisées peuvent toujours avoir le problème, selon la peau qu'elles utilisent.

79
Veeti

La solution de Malcolm fonctionne très bien avec une API> = 9. Voici la solution pour les anciennes API:

L'astuce consiste à créer l'objet de notification standard, puis à parcourir le contentView par défaut créé par Notification.setLatestEventInfo(...). Lorsque vous trouvez le bon TextView, obtenez simplement la tv.getTextColors().getDefaultColor().

Voici le code qui extrait la couleur et la taille du texte par défaut (en pixels de densité à l'échelle - 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;
    }
}

Appelez extractColors ie. dans onCreate () de votre service. Ensuite, lorsque vous créez la notification personnalisée, la couleur et la taille du texte souhaitées sont en notification_text_color et 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);
59
grzaks

La solution consiste à utiliser des styles intégrés. Le style dont vous avez besoin s'appelle TextAppearance.StatusBar.EventContent dans Android 2.3 et Android 4.x. Dans Android 5.x, les notifications de matériel utilisent plusieurs autres styles: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title, et TextAppearance.Material.Notification.Line2. Il vous suffit de définir l'apparence de texte appropriée pour la vue texte et vous obtiendrez les couleurs nécessaires.

Si vous êtes intéressé par la façon dont je suis arrivé à cette solution, voici ma piste de chapelure. Les extraits de code sont tirés de Android 2.3.

  1. Lorsque vous utilisez Notification et définissez le texte à l'aide de moyens intégrés, la ligne suivante crée la mise en page:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.Android.internal.R.layout.status_bar_latest_event_content);
    
  2. La disposition mentionnée contient le View suivant qui est responsable de l'affichage du texte de notification:

    <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. La conclusion est donc que le style nécessaire est TextAppearance.StatusBar.EventContent, dont la définition ressemble à ceci:

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

    Vous devez noter ici que ce style ne fait référence à aucune des couleurs intégrées, donc le moyen le plus sûr consiste à appliquer ce style au lieu d'une couleur intégrée.

Encore une chose: avant Android 2.3 (API niveau 9), il n'y avait ni styles, ni couleurs, il n'y avait que des valeurs codées en dur. Si vous deviez prendre en charge de telles anciennes versions pour certains raison, voir réponse de Gaks .

81
Malcolm

Voici une solution pour toute version du SDK utilisant uniquement des ressources.

res/values ​​/ 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/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: Les valeurs codées en dur sont utilisées pour 2.2-. Des problèmes peuvent donc survenir avec de rares anciens firmwares personnalisés.

17
A-IV

Pour 2.3+ (De documentation Android ):

Utilisez le style Android:TextAppearance.StatusBar.EventContent.Title pour le texte principal.

Utilisez le style Android:TextAppearance.StatusBar.EventContent pour le texte secondaire.

Pour 2.2-, faites quoi Gaks a suggéré dans une autre réponse à ce fil.

Si vous souhaitez compiler avec 2.2 et prendre en charge 2.3+, et prendre en charge toute la variété d'appareils, la solution de Gaks est la seule que je connaisse.

BTW, ce que Google a suggéré d'utiliser la valeur ?android:attr/textColorPrimary pour 2.2-, ne fonctionne pas. Essayez-le simplement à l'aide de l'émulateur. La voie de Gaks est la seule voie.

Plus de ressources: This et this ne fonctionnent pas.

13
AlikElzin-kilaka

Vous devez utiliser les couleurs spécifiées dans Android.R.color

Par exemple: Android.R.color.primary_text_light

Les développeurs personnalisés ROM et Android skin) sont censés les mettre à jour afin que les couleurs de votre application puissent correspondre au reste du système. le texte s'affiche correctement dans tout le système.

2
Austyn Mahoney

J'utilise ceci sur le TextView en question:

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

Il me donne du texte blanc si l'arrière-plan est noir et du texte noir si l'arrière-plan est blanc. Et cela fonctionne au moins aussi loin que l'API 19.

1
Gavin Wright

J'ai trouvé une solution très simple en changeant directement le nom de l'attribut fourni par Android.

Comme vous pouvez le voir dans ce tutoriel: http://www.framentos.com/Android-tutorial/2012/02/20/how-to-create-a-custom-notification-on-Android/ =

Il vous suffit d'utiliser un attribut différent:

<item name="Android:textColor">?android:attr/textColorPrimaryInverse</item>

J'espère que cela peut vous aider!

1
Mauri

Regardez ces instructions: http://developer.Android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Si vous configurez votre couleur d'arrière-plan pour le conteneur LinearLayout, vous pouvez avoir vos couleurs dans la notification pour le texte et l'arrière-plan.

Si la couleur par défaut du texte de notification est définie par l'application de lancement, vous ne pouvez pas la récupérer à partir des paramètres par défaut Android par défaut, sauf si le lanceur partage ces informations.

Cependant, avez-vous essayé de supprimer cette ligne Android: textColor = "# 000" de votre mise en page afin qu'elle puisse obtenir automatiquement la couleur par défaut?

1
Lumis

Je sais que c'est une vieille question mais cela pourrait aider quelqu'un d'autre; ) Je le fais dans mon application et cela fonctionne parfaitement en quelques lignes:

    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;

    }
0
Samet

La solution de @Malckom ne m'a pas aidé chez Lolipop avec un fond de notification sombre à cause de TextAppearance.Material.Notification.Title est une couleur codée en dur par le système. La solution de @grzaks l'a fait, mais avec quelques modifications dans le processus de création de notification:

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

Voici ce qui a fonctionné pour moi pour résoudre cette erreur. Ajoutez ce qui suit à 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>
0
inder