Benutzerdefinierte Benachrichtigungslayouts und Textfarben

81

Meine Anwendung zeigt einige Benachrichtigungen an und abhängig von den Benutzereinstellungen wird möglicherweise ein benutzerdefiniertes Layout in einer Benachrichtigung verwendet. Es funktioniert gut, aber es gibt ein kleines Problem - Textfarben . Standard Android und fast alle Hersteller-Skins verwenden schwarzen Text vor einem hellen Hintergrund für Benachrichtigungstext, Samsung jedoch nicht: Ihr Benachrichtigungs-Pulldown hat einen dunklen Hintergrund und der Text im Standard-Benachrichtigungslayout ist weiß.

Dies verursacht also ein Problem: Die Benachrichtigungen, die keine ausgefallenen Layouts verwenden, werden gut angezeigt, aber die Benachrichtigungen, die ein benutzerdefiniertes Layout verwenden, sind schwer zu lesen, da der Text schwarz anstelle des Standardweiß ist. Sogar die offizielle Dokumentation legt nur eine #000Farbe für a fest TextView, sodass ich dort keine Hinweise finden konnte.

Ein Benutzer war so freundlich, einen Screenshot des Problems zu machen:

Bildschirmfoto

So wie verwende ich die Standard - Benachrichtigung Textfarbe aus dem Gerät in meinen Layouts? Ich möchte lieber nicht anfangen, die Textfarbe basierend auf dem Telefonmodell dynamisch zu ändern, da dies viele Aktualisierungen erfordert und Personen mit benutzerdefinierten ROMs je nach verwendetem Skin möglicherweise immer noch das Problem bekommen.

Veeti
quelle
9
Bild nicht mehr verfügbar
Amir Uval
Laden Sie das Bild nach Möglichkeit erneut hoch.
Maciej Gol

Antworten:

62

Die Lösung von Malcolm funktioniert gut mit API> = 9. Hier ist die Lösung für ältere API:

Der Trick besteht darin, das Standardbenachrichtigungsobjekt zu erstellen und dann den von contentViewerstellten Standard zu durchlaufen Notification.setLatestEventInfo(...). Wenn Sie die richtige Textansicht gefunden haben, holen Sie sich einfach die tv.getTextColors().getDefaultColor().

Hier ist der Code, der die Standardtextfarbe und -größe extrahiert (in Pixeln mit skalierter Dichte - 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;
    }
}

Rufen Sie extractColorsdh. in onCreate () Ihres Dienstes. Wenn Sie dann die benutzerdefinierte Benachrichtigung erstellen, geben Sie die gewünschte Farbe und Textgröße ein notification_text_colorund 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
quelle
1
+1 tolle Antwort. Funktioniert gut. Mir ist aufgefallen, dass es anscheinend zwei verschiedene Standardfarben gibt - für den Titel und für den Hauptinhalt. Ich möchte beide abrufen, konnte aber nur mit dieser Methode die Titelfarbe ermitteln - die Iteration scheint nur 1 Textfeld zu finden. Irgendwelche Ideen?
Einsiedler
1
Ich sehe das gleiche wie @Raw, nur eine Textansicht. Ich habe "Utest" durch einen anderen Suchtipp (und eine andere Zeichenfolge) ersetzt. Es wird nur die eine Textansicht gefunden und sie stimmt mit COLOR_SEARCH_RECURSE_TIP überein. Irgendwelche Hinweise? Vielen Dank.
Ciscogambo
6
Der Grund, warum nur einer gefunden wird, ist ein Fehler in "return recurseGroup ((ViewGroup) gp.getChildAt (i))"; - Die Methode sollte nur zurückgeben, wenn die innere "recurseGroup" true zurückgibt. Es sollte sein: "if (recurseGroup ((ViewGroup) gp.getChildAt (i))) gibt true zurück;". Vielen Dank für die Lösung - großartiges Denken.
AlikElzin-Kilaka
9
Vielen Dank für diese Antwort, es war sehr sehr hilfreich. Für alle Interessierten habe ich eine kurze Klasse zusammengestellt, in die sowohl der Titel als auch die Textfarbe / -größe basierend auf Gaks Antwort abgerufen werden können. Es ist hier zu finden: pastebin.com/sk08QGxs
NuSkooler
3
Hüten Sie sich vor diesem Satz, da er nicht wahr ist (getestet in einem Galaxy Ace mit API-Level 10) : Solution by Malcolm works fine with API>=9. Sie wissen, Android und Hersteller sind eine schwierige Sache. Verwenden Sie diese Lösung für jede Plattform.
cprcrack
82

Die Lösung besteht darin, integrierte Stile zu verwenden. Der Stil, den Sie benötigen, wird TextAppearance.StatusBar.EventContentin Android 2.3 und Android 4.x aufgerufen. In Android 5.x Material Benachrichtigungen verwenden mehrere andere Stile: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title, undTextAppearance.Material.Notification.Line2 . Stellen Sie einfach das entsprechende Texterscheinungsbild für die Textansicht ein, und Sie erhalten die erforderlichen Farben.

Wenn Sie interessiert sind, wie ich zu dieser Lösung gekommen bin, finden Sie hier meine Spur von Semmelbröseln. Die Code-Auszüge stammen aus Android 2.3.

  1. Wenn Sie Notificationden Text mit integrierten Mitteln verwenden und festlegen, wird in der folgenden Zeile das Layout erstellt:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.android.internal.R.layout.status_bar_latest_event_content);
  2. Das erwähnte Layout enthält Folgendes, Viewdas für die Anzeige des Benachrichtigungstextes verantwortlich ist:

    <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. Die Schlussfolgerung ist also, dass der benötigte Stil lautet TextAppearance.StatusBar.EventContent, welche Definition so aussieht:

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

    Sie sollten hier beachten, dass dieser Stil nicht auf eine der integrierten Farben verweist. Daher ist es am sichersten, diesen Stil anstelle einer integrierten Farbe anzuwenden.

Noch etwas: Vor Android 2.3 (API Level 9) gab es weder Stile noch Farben, es gab nur fest codierte Werte. Wenn Sie aus irgendeinem Grund solche alten Versionen unterstützen müssen, lesen Sie die Antwort von Gaks .

Malcolm
quelle
Ich glaube nicht, dass ich diese Antwort verstehe. Der letzte Satz besagt, dass es keine Farbreferenz gibt, die dafür verwendet werden kann. Welche Farbe sollte in diesem Fall verwendet werden?
Steve Pomeroy
Trotzdem habe ich im Änderungsprotokoll von Android festgestellt, dass erst ab API-Level 9 das Android: textAppearance = "@ androidstyle / TextAppearance.StatusBar.EventContent" veröffentlicht wurde. Vorher war es versteckt.
Steve Pomeroy
1
Es war vor Android 2.3 nicht versteckt, es existierte einfach nicht. Damals gab es einen fest codierten Wert im Layout, und wenn der Gerätehersteller beschloss, ihn zu ändern, konnten Sie nichts dagegen tun. Es gab keine Farben oder Stile, über die Sie auf diesen Wert zugreifen konnten. Im Moment haben Sie noch keine Farben, aber Sie haben einen Stil, den Sie anwenden können, um diese bestimmte Textfarbe zu erhalten. Sinn ergeben? :)
Malcolm
3
Welcher lokale Stil? Der Stil in meiner Antwort stammt direkt aus der Android-Quelle. Sie wenden es wie jeden anderen integrierten Stil ( style="@android:style/TextAppearance.StatusBar.EventContent") an und erhalten die erforderliche Farbe für den Text. Es wird #ff6b6b6bim Fall von Vanille-Android sein, oder welche Farbe auch immer dort vom Gerätehersteller eingestellt wurde.
Malcolm
4
Nur um andere wissen zu lassen, funktioniert dies nicht auf Android 6+
iGoDa
17

Hier ist eine Lösung für jede SDK-Version, die nur Ressourcen verwendet.

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

PS: Für 2.2- werden hartcodierte Werte verwendet. Daher können Probleme mit einigen seltenen alten benutzerdefinierten Firmwares auftreten.

A-IV
quelle
sicher, dass die Textfarbe benötigt wird? der Elternteil setzt es schon, nein?
Android-Entwickler
13

Für 2.3+ (aus der Android-Dokumentation ):

Verwenden Sie den Stil android:TextAppearance.StatusBar.EventContent.Titlefür den Primärtext.

Verwenden Sie den Stil android:TextAppearance.StatusBar.EventContentfür den sekundären Text.

Tun Sie für 2.2-, was Gaks in einer anderen Antwort auf diesen Thread vorgeschlagen hat.

Wenn Sie gegen 2.2 kompilieren und 2.3+ unterstützen und die Vielzahl der Geräte unterstützen möchten, ist die Lösung von Gaks die einzige, die ich kenne.

Übrigens, was Google über die Verwendung des Werts ?android:attr/textColorPrimaryfür 2.2- vorgeschlagen hat, funktioniert nicht. Probieren Sie es einfach mit dem Emulator aus. Gaks Weg ist der einzige Weg.

Weitere Ressourcen: Dies und das funktioniert nicht.

AlikElzin-Kilaka
quelle
5
Ihre Anweisungen über 2.3 funktionierten nicht für Android 5. Sie erzeugten weißen Text auf weißem Hintergrund.
Sam
5

Ich verwende dies in der fraglichen Textansicht:

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

Es gibt mir weißen Text, wenn der Hintergrund schwarz ist, und schwarzen Text, wenn der Hintergrund weiß ist. Und es funktioniert mindestens so weit zurück wie API 19.

Gavin Wright
quelle
2

Sie sollten die in angegebenen Farben verwenden android.R.color

Beispielsweise: android.R.color.primary_text_light

Benutzerdefinierte ROM-Entwickler und Android-Skin-Designer sollen diese aktualisieren, damit die Farben Ihrer App mit dem Rest des Systems übereinstimmen können. Dazu gehört, dass Sie sicherstellen, dass Ihr Text im gesamten System ordnungsgemäß angezeigt wird.

Austyn Mahoney
quelle
Von welcher Farbe soll ich verwenden android.R.color? Alle Textfarben haben sowohl "dunkle" als auch "helle" Variationen.
Veeti
1
Ich habe kein Gerät mit einem benutzerdefinierten Thema, daher kann ich nicht wirklich testen, welches verwendet werden soll. Ich würde sagen, versuchen Sie beide und sehen Sie, welche für Sie funktioniert.
Austyn Mahoney
1

Schauen Sie sich diese Anleitung an: Sehen Sie sich http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Wenn Sie Ihre Hintergrundfarbe für den LinearLayout-Container eingerichtet haben, können Sie Ihre Farben in Benachrichtigung für Text und der Hintergrund.

Wenn die Standardfarbe für den Benachrichtigungstext von der Launcher-Anwendung definiert wird, können Sie sie nicht aus den Standardeinstellungen für Android abrufen, es sei denn, der Launcher teilt diese Informationen.

Haben Sie jedoch versucht, diese Zeile android: textColor = "# 000" aus Ihrem Layout zu entfernen, damit sie automatisch die Standardfarbe erhält?

Lumis
quelle
1
Das Entfernen der Textfarbe hilft nicht - die Standardeinstellung stimmt nicht mit den Benachrichtigungsfarben überein.
Veeti
Haben Sie versucht, den Hintergrund zu ändern? Ich denke, das ist ein ernstes Problem und es ist gut, dass Sie es angesprochen haben. Haben Sie versucht, Google Entwickler Forum / Gruppen?
Lumis
1

Ich weiß, dass es eine alte Frage ist, aber sie könnte jemand anderem helfen. ) Ich mache das in meiner App und das funktioniert in wenigen Zeilen perfekt:

    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
quelle
0

Die Lösung von @Malckom hat mir bei Lolipop mit dunklem Benachrichtigungshintergrund aufgrund von TextAppearance.Material.Notification.Title nicht geholfen. Die Lösung von @grzaks hat dies getan, jedoch mit einigen Änderungen beim Erstellen von Benachrichtigungen:

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
quelle
0

Hier ist, was für mich funktioniert hat, um diesen Fehler zu beheben. Fügen Sie der Datei styles.xml Folgendes hinzu

    <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
quelle