Bố cục thông báo tùy chỉnh và màu văn bản


81

Ứng dụng của tôi hiển thị một số thông báo và tùy thuộc vào sở thích của người dùng, ứng dụng có thể sử dụng bố cục tùy chỉnh trong thông báo. Nó hoạt động tốt, nhưng có một vấn đề nhỏ - màu sắc văn bản . Android gốc và hầu hết các giao diện của nhà sản xuất đều sử dụng văn bản màu đen trên nền sáng cho văn bản thông báo, nhưng Samsung thì không: thanh kéo thông báo của họ có nền tối và văn bản trong bố cục thông báo mặc định là màu trắng.

Vì vậy, điều này gây ra một vấn đề: các thông báo không sử dụng bất kỳ bố cục ưa thích nào hiển thị tốt, nhưng thông báo sử dụng bố cục tùy chỉnh thì khó đọc vì văn bản có màu đen thay vì màu trắng mặc định. Ngay cả tài liệu chính thức cũng chỉ đặt #000màu cho a TextView, vì vậy tôi không thể tìm thấy bất kỳ gợi ý nào ở đó.

Một người dùng đủ tốt để chụp ảnh màn hình của sự cố:

Ảnh chụp màn hình

Vậy làm cách nào để sử dụng màu văn bản thông báo mặc định từ thiết bị trong bố cục của tôi? Tôi không muốn bắt đầu tự động thay đổi màu văn bản dựa trên kiểu điện thoại, vì điều đó đòi hỏi phải cập nhật nhiều và những người có ROM tùy chỉnh vẫn có thể gặp sự cố, tùy thuộc vào da họ đang sử dụng.


9
hình ảnh không còn có sẵn
Amir Uval

Hãy tải lại hình ảnh nếu có thể.
Maciej Gol

Câu trả lời:


63

Giải pháp của Malcolm hoạt động tốt với API> = 9. Đây là giải pháp cho API cũ hơn:

Bí quyết là tạo đối tượng thông báo tiêu chuẩn và sau đó duyệt qua đối tượng mặc định contentViewđược tạo bởi Notification.setLatestEventInfo(...). Khi bạn tìm thấy TextView phù hợp, chỉ cần lấy tv.getTextColors().getDefaultColor().

Đây là mã trích xuất màu văn bản và kích thước văn bản mặc định (tính bằng pixel mật độ được chia tỷ lệ - 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;
    }
}

Gọi extractColorstức là. trong onCreate () của dịch vụ của bạn. Sau đó, khi bạn tạo thông báo tùy chỉnh, màu và kích thước văn bản bạn muốn sẽ ở trong đó notification_text_colornotification_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);

1
+1 câu trả lời tuyệt vời. Hoạt động tốt. Tôi nhận thấy dường như có 2 màu mặc định khác nhau - cho tiêu đề và cho nội dung chính. Tôi muốn tìm nạp cả hai, nhưng chỉ có thể lấy màu tiêu đề bằng phương pháp này - phép lặp dường như chỉ tìm thấy 1 hộp văn bản. Có ý kiến ​​gì không?
Hermit

1
Tôi thấy giống như @Raw, chỉ có một TextView. Tôi đã thay thế "Utest" bằng một mẹo tìm kiếm khác (và bằng một chuỗi khác). Nó chỉ tìm thấy một TextView và nó khớp với COLOR_SEARCH_RECURSE_TIP. Bất kỳ gợi ý? Cám ơn.
ciscogambo 27/10/11

6
Lý do nó chỉ tìm thấy một là một lỗi trong "return recurseGroup ((ViewGroup) gp.getChildAt (i));" - phương thức chỉ nên trả về nếu "recurseGroup" bên trong trả về true. Nó phải là: "if (recurseGroup ((ViewGroup) gp.getChildAt (i))) trả về true;". Cảm ơn vì giải pháp - suy nghĩ tuyệt vời.
AlikElzin-kilaka

9
Cảm ơn vì câu trả lời này, nó rất hữu ích. Đối với bất kỳ ai quan tâm, tôi đã tập hợp một lớp học nhanh hơn có thể được đưa vào để tìm nạp cả tiêu đề và màu sắc / kích thước văn bản dựa trên câu trả lời của Gaks. Nó có thể được tìm thấy ở đây: pastebin.com/sk08QGxs
NuSkooler

3
Hãy cẩn thận với câu này vì nó không đúng (được thử nghiệm trong Galaxy Ace với API cấp 10) : Solution by Malcolm works fine with API>=9. Bạn biết đấy, Android và các nhà sản xuất là một thứ khó khăn. Sử dụng giải pháp này cho mọi nền tảng.
cprcrack 29/12/13

83

Giải pháp là sử dụng các kiểu có sẵn. Kiểu bạn cần được gọi TextAppearance.StatusBar.EventContenttrong Android 2.3 và Android 4.x. Trong Android 5.x thông báo tài liệu sử dụng nhiều phong cách khác: TextAppearance.Material.Notification, TextAppearance.Material.Notification.Title, và TextAppearance.Material.Notification.Line2. Chỉ cần đặt giao diện văn bản thích hợp cho chế độ xem văn bản, và bạn sẽ nhận được các màu cần thiết.

Nếu bạn quan tâm đến cách tôi đã đưa ra giải pháp này, đây là dấu vết của tôi về đường dẫn. Các đoạn mã được lấy từ Android 2.3.

  1. Khi bạn sử dụng Notificationvà đặt văn bản bằng cách sử dụng các phương tiện có sẵn, dòng sau sẽ tạo bố cục:

    RemoteViews contentView = new RemoteViews(context.getPackageName(),
            com.android.internal.R.layout.status_bar_latest_event_content);
    
  2. Bố cục được đề cập có chứa phần sau Viewchịu trách nhiệm xem văn bản thông báo:

    <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. Vì vậy, kết luận là phong cách cần thiết là TextAppearance.StatusBar.EventContent, định nghĩa trông giống như sau:

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

    Bạn nên lưu ý ở đây rằng phong cách này không thực sự tham chiếu đến bất kỳ màu nào được tích hợp sẵn, vì vậy cách an toàn nhất là áp dụng phong cách này thay vì một số màu tích hợp.

Một điều nữa: trước Android 2.3 (API Cấp 9), không có kiểu dáng hay màu sắc, chỉ có các giá trị được mã hóa cứng. Nếu bạn tình cờ phải hỗ trợ các phiên bản cũ như vậy vì lý do nào đó, hãy xem câu trả lời của Gaks .


Tôi không nghĩ rằng tôi hiểu câu trả lời này. Câu cuối cùng nói rằng không có tham chiếu màu nào có thể được sử dụng cho việc này. Màu gì nên được sử dụng trong trường hợp này?
Steve Pomeroy

Điều đó nói rằng, tôi nhận thấy trong bảng thay đổi của Android rằng chỉ ở cấp độ API 9, android: textAppearance = "@ androidstyle / TextAppearance.StatusBar.EventContent" mới được công khai. Trước đó, nó đã được ẩn.
Steve Pomeroy

1
Nó không bị ẩn trước Android 2.3, đơn giản là nó không tồn tại. Hồi đó, có một giá trị được mã hóa cứng trong bố cục và nếu nhà cung cấp thiết bị quyết định thay đổi nó, bạn sẽ không thể làm gì với nó. Không có màu sắc hoặc kiểu dáng mà bạn có thể truy cập giá trị này. Hiện tại, bạn vẫn chưa có màu nào, nhưng bạn có một kiểu, bạn có thể áp dụng để có được màu văn bản cụ thể này. Có lý? :)
Malcolm

3
Phong cách địa phương nào? Phong cách trong câu trả lời của tôi được lấy trực tiếp từ nguồn Android. Bạn áp dụng nó như bất kỳ kiểu cài sẵn nào khác ( style="@android:style/TextAppearance.StatusBar.EventContent") và lấy màu cần thiết cho văn bản. Nó sẽ là #ff6b6b6btrong trường hợp của Android màu vani, hoặc bất kỳ màu nào được đặt ở đó bởi nhà cung cấp thiết bị.
Malcolm

4
Chỉ để cho những người khác biết, điều này không hoạt động trên Android 6+
iGoDa 23/09/15

17

Đây là giải pháp cho bất kỳ phiên bản SDK nào chỉ sử dụng tài nguyên.

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: Các giá trị được mã hóa cứng được sử dụng cho 2.2-. Vì vậy, sự cố có thể xảy ra với một số firmware tùy chỉnh cũ hiếm gặp.


chắc chắn màu văn bản là cần thiết? cha mẹ đã đặt nó, không?
nhà phát triển android

13

Đối với 2.3+ (Từ tài liệu Android ):

Sử dụng kiểu android:TextAppearance.StatusBar.EventContent.Titlecho văn bản chính.

Sử dụng kiểu android:TextAppearance.StatusBar.EventContentcho văn bản phụ.

Đối với 2.2-, hãy làm những gì Gaks đề xuất trong một câu trả lời khác cho chủ đề này.

Nếu bạn muốn biên dịch với 2.2 và hỗ trợ 2.3+, đồng thời hỗ trợ tất cả các loại thiết bị khác nhau, giải pháp của Gaks là giải pháp duy nhất mà tôi biết.

BTW, những gì Google đề xuất về việc sử dụng giá trị ?android:attr/textColorPrimarycho 2.2-, không hoạt động. Chỉ cần thử nó bằng cách sử dụng trình giả lập. Cách của Gaks là cách duy nhất.

Tài nguyên khác: Điều nàyđiều này không hoạt động.


5
Hướng dẫn 2.3+ của bạn không hoạt động với Android 5. Nó tạo ra văn bản màu trắng trên nền trắng.
Sam

5

Tôi sử dụng cái này trên TextView được đề cập:

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

Nó cung cấp cho tôi văn bản màu trắng nếu nền là màu đen và văn bản màu đen nếu nền là màu trắng. Và nó hoạt động ít nhất là từ API 19 trở lại đây.


2

Bạn nên sử dụng các màu được chỉ định trong android.R.color

Ví dụ: android.R.color.primary_text_light

Các nhà phát triển ROM tùy chỉnh và nhà thiết kế giao diện Android phải cập nhật những thứ này để màu sắc ứng dụng của bạn có thể phù hợp với phần còn lại của hệ thống. Điều này bao gồm việc đảm bảo văn bản của bạn hiển thị chính xác trên toàn hệ thống.


Tôi phải sử dụng màu android.R.colorgì? Tất cả các màu văn bản có cả biến thể "tối" và "sáng".
Veeti

1
Tôi không có thiết bị có chủ đề tùy chỉnh trên đó, vì vậy tôi không thể thực sự kiểm tra xem nên sử dụng chủ đề nào. Tôi muốn nói hãy thử cả hai và xem cái nào phù hợp với bạn.
Austyn Mahoney

1

Hãy xem hướng dẫn sau: http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView Nếu bạn thiết lập màu nền của mình cho vùng chứa LinearLayout thì bạn có thể có màu của mình trong thông báo cho văn bản và bối cảnh.

Nếu màu mặc định cho văn bản thông báo được xác định bởi ứng dụng trình khởi chạy thì bạn không thể truy xuất màu đó từ cài đặt mặc định của android trừ khi trình khởi chạy làm rõ thông tin này.

Tuy nhiên, bạn đã thử xóa dòng android: textColor = "# 000" này khỏi bố cục của mình để nó có thể tự động nhận màu mặc định chưa?


1
Loại bỏ màu văn bản không giúp ích gì - mặc định không khớp với màu thông báo.
Veeti

Bạn đã thử thay đổi nền? Tôi nghĩ đây là một vấn đề nghiêm trọng và thật tốt là bạn đã đưa ra nó. Bạn đã thử diễn đàn / nhóm nhà phát triển của Google chưa?
Lumis


1

Tôi biết đó là một câu hỏi cũ nhưng nó có thể giúp ích cho người khác; ) Tôi làm điều này trong ứng dụng của mình và nó hoạt động hoàn hảo trong một số dòng:

    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

Giải pháp từ @Malckom đã không giúp tôi ở Lolipop với nền thông báo tối vì TextAppearance.Material.Notification.Title là màu được mã hóa cứng của hệ thống. Giải pháp từ @grzaks đã làm, nhưng với một số thay đổi trong quá trình tạo thông báo:

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

Đây là những gì đã làm việc để tôi giải quyết lỗi này. Thêm phần sau vào 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

Trong bố cục có thể mở rộng hoặc cắt ghép của bạn, hãy đặt android:backgroundlàm "@android:color/transparent"vì điều này sẽ tự động lấy màu chủ đề thông báo thiết bị của bạn và đặt làm nền

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

Và màu textview của bạn xác định màu đen và trắng như trong Resource/colortệp trong tệp màu đơn giản và cũng như tệp màu chế độ ban đêm

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.