Niestandardowe układy powiadomień i kolory tekstu

82

Moja aplikacja wyświetla niektóre powiadomienia iw zależności od preferencji użytkownika może używać w powiadomieniu niestandardowego układu. Działa dobrze, ale jest mały problem - kolory tekstu . Standardowe skórki Androida i prawie wszystkie skórki producentów używają czarnego tekstu na jasnym tle do tekstu powiadomienia, ale Samsung nie: ich menu rozwijane powiadomień ma ciemne tło, a tekst w domyślnym układzie powiadomień jest biały.

To powoduje problem: powiadomienia, które nie używają żadnych fantazyjnych układów, wyświetlają się dobrze, ale ten, który używa niestandardowego układu, jest trudny do odczytania, ponieważ tekst jest czarny zamiast domyślnego białego. Nawet oficjalna dokumentacja ustawia tylko #000kolor a TextView, więc nie mogłem znaleźć tam żadnych wskazówek.

Użytkownik był na tyle uprzejmy, że wykonał zrzut ekranu problemu:

Zrzut ekranu

Jak więc w moich układach używać domyślnego koloru tekstu powiadomienia z urządzenia ? Wolałbym nie zaczynać dynamicznie zmieniać koloru tekstu w oparciu o model telefonu, ponieważ wymaga to wielu aktualizacji, a osoby z niestandardowymi pamięciami ROM mogą nadal mieć problem, w zależności od używanej skóry.

Veeti
źródło
10
obraz nie jest już dostępny
Amir Uval
Jeśli to możliwe, prześlij ponownie obraz.
Maciej Gol

Odpowiedzi:

63

Rozwiązanie autorstwa Malcolma działa dobrze z API> = 9. Oto rozwiązanie dla starszego interfejsu API:

Sztuczka polega na utworzeniu standardowego obiektu powiadomienia, a następnie przejściu do domyślnego contentViewutworzonego przez Notification.setLatestEventInfo(...). Gdy znajdziesz odpowiedni TextView, po prostu pobierz plik tv.getTextColors().getDefaultColor().

Oto kod, który wyodrębnia domyślny kolor tekstu i rozmiar tekstu (w pikselach o skalowanej gęstości - 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;
    }
}

Zadzwoń extractColorstj. w onCreate () Twojej usługi. Następnie podczas tworzenia powiadomienia niestandardowego należy określić żądany kolor i rozmiar tekstu notification_text_colororaz 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);
grzaki
źródło
1
+1 świetna odpowiedź. Działa dobrze. Zauważyłem, że są 2 różne domyślne kolory - dla tytułu i dla głównej treści. Chcę pobrać oba, ale udało mi się uzyskać tylko kolor tytułu za pomocą tej metody - iteracja wydaje się znajdować tylko 1 pole tekstowe. Jakieś pomysły?
Pustelnik
1
Widzę to samo, co @Raw, tylko jeden TextView. Zastąpiłem „Utest” inną wskazówką dotyczącą wyszukiwania (i innym ciągiem znaków). Znajduje tylko jeden TextView i pasuje do COLOR_SEARCH_RECURSE_TIP. Jakieś wskazówki? Dzięki.
ciscogambo
6
Powodem, dla którego znajduje tylko jeden, jest błąd w "return recurseGroup ((ViewGroup) gp.getChildAt (i));" - metoda powinna zwrócić tylko wtedy, gdy wewnętrzna „recurseGroup” zwróciła true. Powinno być: "if (recurseGroup ((ViewGroup) gp.getChildAt (i))) return true;". Dzięki za rozwiązanie - świetne myślenie nieszablonowe.
AlikElzin-kilaka,
9
Dzięki za tę odpowiedź, była bardzo pomocna. Dla wszystkich zainteresowanych przygotowałem szybkie zajęcia, które można wrzucić, aby pobrać zarówno tytuł, jak i kolor / rozmiar tekstu na podstawie odpowiedzi Gaks. Można go znaleźć tutaj: pastebin.com/sk08QGxs
NuSkooler
3
Strzeż się tego zdania, bo to nie prawda (testowane na Galaxy Ace z API poziomu 10) Solution by Malcolm works fine with API>=9. Wiesz, Android i producenci to trudna sprawa. Użyj tego rozwiązania na każdej platformie.
cprcrack
83

Rozwiązaniem jest użycie wbudowanych stylów. Styl, którego potrzebujesz, jest nazywany TextAppearance.StatusBar.EventContentw Androidzie 2.3 i Androidzie 4.x. W Androidzie 5.x materialne powiadomienia użyć kilku innych stylów: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title, i TextAppearance.Material.Notification.Line2. Wystarczy ustawić odpowiedni wygląd tekstu dla widoku tekstu, a otrzymasz niezbędne kolory.

Jeśli jesteś zainteresowany, jak doszedłem do tego rozwiązania, oto mój ślad bułki tartej. Fragmenty kodu pochodzą z systemu Android 2.3.

  1. Podczas używania Notificationi ustawiania tekstu przy użyciu środków wbudowanych następujący wiersz tworzy układ:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.android.internal.R.layout.status_bar_latest_event_content);
    
  2. Wspomniany układ zawiera następujące elementy, Viewktóre są odpowiedzialne za przeglądanie tekstu powiadomienia:

    <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. Wniosek jest taki, że potrzebny jest styl TextAppearance.StatusBar.EventContent, którego definicja wygląda następująco:

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

    Należy zauważyć, że ten styl w rzeczywistości nie odnosi się do żadnego z wbudowanych kolorów, więc najbezpieczniejszym sposobem jest zastosowanie tego stylu zamiast niektórych wbudowanych kolorów.

Jeszcze jedno: przed Androidem 2.3 (poziom API 9) nie było ani stylów, ani kolorów, były tylko wartości zakodowane na stałe. Jeśli z jakiegoś powodu musisz obsługiwać takie stare wersje, zobacz odpowiedź Gaks .

Malcolm
źródło
Myślę, że nie rozumiem tej odpowiedzi. Ostatnie zdanie stwierdza, że ​​nie ma odniesienia do koloru, którego można by do tego użyć. Jakiego koloru należy użyć w tym przypadku?
Steve Pomeroy
To powiedziawszy, zauważyłem w dzienniku zmian Androida, że ​​dopiero od poziomu API 9, android: textAppearance = "@ androidstyle / TextAppearance.StatusBar.EventContent" został upubliczniony. Wcześniej był ukryty.
Steve Pomeroy
1
Nie był ukryty przed Androidem 2.3, po prostu nie istniał. Wtedy w układzie była zakodowana wartość i gdyby sprzedawca urządzenia zdecydował się ją zmienić, nie byłbyś w stanie nic z tym zrobić. Nie było kolorów ani stylów, przez które można było uzyskać dostęp do tej wartości. W tej chwili nadal nie masz kolorów, ale masz styl, który możesz zastosować, aby uzyskać ten konkretny kolor tekstu. Ma sens? :)
Malcolm,
3
Jaki lokalny styl? Styl mojej odpowiedzi pochodzi prosto ze źródła Androida. Stosujesz go jak każdy inny wbudowany styl ( style="@android:style/TextAppearance.StatusBar.EventContent") i uzyskujesz odpowiedni kolor dla tekstu. Będzie to miało miejsce #ff6b6b6bw przypadku waniliowego Androida lub innego koloru ustawionego przez dostawcę urządzenia.
Malcolm,
4
Aby inni wiedzieli, to nie działa na Androidzie 6+
iGoDa
17

Oto rozwiązanie dla dowolnej wersji SDK korzystającej tylko z zasobów.

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: wartości zakodowane na stałe są używane dla 2.2-. Dlatego mogą wystąpić problemy z niektórymi rzadkimi, starymi niestandardowymi oprogramowaniem układowym.

A-IV
źródło
czy kolor tekstu jest potrzebny? rodzic już to ustawia, nie?
programista Androida
13

Wersja 2.3+ (z dokumentacji systemu Android ):

Użyj stylu android:TextAppearance.StatusBar.EventContent.Titledla tekstu podstawowego.

Użyj stylu android:TextAppearance.StatusBar.EventContentdla tekstu dodatkowego.

W przypadku wersji 2.2- zrób to, co zasugerował Gaks w innej odpowiedzi na ten wątek.

Jeśli chcesz kompilować z wersją 2.2 i obsługiwać 2.3+ i obsługiwać wszystkie różne urządzenia, rozwiązanie Gaks jest jedynym, jakie znam.

BTW, to, co sugerował Google przy używaniu wartości ?android:attr/textColorPrimarydla 2.2-, nie działa. Po prostu spróbuj za pomocą emulatora. Droga Gaksa jest jedyną drogą.

Więcej zasobów: to i to nie działa.

AlikElzin-kilaka
źródło
5
Twoje instrukcje w wersji 2.3+ nie działały na Androidzie 5. Spowoduje to wyświetlenie białego tekstu na białym tle.
Sam
6

Używam tego w omawianym TextView:

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

Daje mi biały tekst, jeśli tło jest czarne, a czarny tekst, jeśli tło jest białe. I działa przynajmniej od API 19.

Gavin Wright
źródło
2

Powinieneś używać kolorów określonych w android.R.color

Na przykład: android.R.color.primary_text_light

Niestandardowi programiści ROM i projektanci skór dla Androida powinni je aktualizować, aby kolory Twojej aplikacji były zgodne z resztą systemu. Obejmuje to zapewnienie prawidłowego wyświetlania tekstu w całym systemie.

Austyn Mahoney
źródło
Z jakiego koloru mam użyć android.R.color? Wszystkie kolory tekstu mają zarówno „ciemne”, jak i „jasne” odmiany.
Veeti
1
Nie mam urządzenia z niestandardowym motywem, więc nie mogę tak naprawdę przetestować, którego użyć. Powiedziałbym, że spróbuj obu i zobacz, który z nich działa dla Ciebie.
Austyn Mahoney,
1

Spójrz na te instrukcje: http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Jeśli ustawisz kolor tła dla kontenera LinearLayout, możesz mieć kolory w powiadomieniach o tekście i tło.

Jeśli domyślny kolor tekstu powiadomienia jest zdefiniowany przez aplikację uruchamiającą, nie można go pobrać z domyślnych ustawień Androida, chyba że program uruchamiający udostępnia te informacje.

Czy jednak próbowałeś usunąć ten wiersz android: textColor = "# 000" ze swojego układu, aby mógł automatycznie uzyskać domyślny kolor?

Lumis
źródło
1
Usunięcie koloru tekstu nie pomaga - domyślny kolor nie pasuje do kolorów powiadomień.
Veeti
Czy próbowałeś zmienić tło? Myślę, że to poważny problem i dobrze, że o nim wspomniałeś. Czy próbowałeś / aś forum / grupy programistów Google?
Lumis
1

Wiem, że to stare pytanie, ale mogłoby pomóc komuś innemu; ) Robię to w mojej aplikacji i działa to idealnie w kilku wierszach:

    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
źródło
0

Rozwiązanie od @Malckom nie pomogło mi w Lolipopie z ciemnym tłem powiadomień z powodu TextAppearance.Material.Notification.Title to systemowy kolor zakodowany na stałe. Rozwiązanie od @grzaks tak, ale z pewnymi zmianami w procesie tworzenia powiadomień:

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
źródło
0

Oto, co pomogło mi rozwiązać ten błąd. Dodaj następujące elementy do 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
źródło
0

W układzie rozwijanym lub zwiniętym ustawionym android:backgroundjako, "@android:color/transparent"ponieważ automatycznie przyjmuje kolor motywu powiadomienia urządzenia i ustawia go jako tło

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

Kolor widoku tekstu definiuje czerń i biel, jak w Resource/colorpliku w prostym pliku kolorów, a także w pliku kolorów w trybie nocnym

ADITYA YOGESHBHAI DALWADI
źródło