web-dev-qa-db-ja.com

Android Lollipopは白です。どうすれば変更できますか?

アプリにメッセージの通知を表示したい。以前のバージョンのAndroidはすべて問題ありませんが、Lollipopでは通知の背景が白です。layout_message_notification.xmlの通知レイアウトにこのXMLコードを使用しました。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/layout_messageNotification"
    Android:orientation="horizontal"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@Android:color/transparent">

    <LinearLayout
        Android:layout_width="0dp"
        Android:layout_weight=".2"
        Android:layout_height="wrap_content"
        Android:background="@Android:color/transparent">

        <ImageView
            Android:layout_width="fill_parent"
            Android:layout_height="wrap_content"
            Android:scaleType="fitCenter"
            Android:src="@drawable/message_icon"/>

    </LinearLayout>

    <LinearLayout
        Android:layout_width="0dp"
        Android:layout_weight=".8"
        Android:layout_height="wrap_content"
        Android:background="@Android:color/transparent">

        <TextView
            Android:id="@+id/textView_notification_title"
            Android:layout_width="fill_parent"
            Android:layout_height="fill_parent"
            Android:gravity="right|center_vertical"
            Android:layout_margin="15dp"/>

    </LinearLayout>

</LinearLayout>

Lollipopでの通知は次のように表示されます。 notification style in Lollipop

以前のバージョンのAndroidのように、通知の背景を暗くまたは透明にするにはどうすればよいですか?

13
Mansour

この回答は、通知の背景色を変更するhackyメソッドについて説明しています。
注意してください:これは文書化されていない回避策です。これはリフレクションに基づいており、カスタムファームウェアでは壊れている可能性があります。 AndroidLollipopおよびMarshmallowバージョンにのみ適用されます。 Android N以降のバージョンではは機能しません。回避する重大な理由がない限り、デフォルトの色を使用することをお勧めします。

[〜#〜]なぜ[〜#〜]
カスタム通知の背景色を設定する合法的な方法はありません。 Googleは、マテリアルデザインに従って、優先度に応じて通知を白またはライトグレーにする必要があると判断しました。ただし、Googleはこのルールに2つの例外も設けました。

  1. 古いアプリケーションの通知は黒の背景で表示されます。
  2. MediaStyleで作成された通知は、任意の色にすることができます。

2番目の例外の結果として、そのような制限は非論理的で不合理に見えます。それが、Googleが推奨する(または強制する)色の代わりにカスタム色を使用したい唯一の言い訳です。

中身
BaseStatusBarを調べて、この制限がどのように課されているかを確認しましょう。通知の背景色が計算される唯一の場所は applyColorsAndBackgroundsメソッド です。
ifステートメントの最初のブランチは、レガシーアプリケーション用です。ここに到達する唯一の方法は、アプリケーションのターゲットSDKをBuild.VERSION_CODES.Lollipopの下に設定することです。この場合、背景は黒くなります。
entry.row.setTintColorステートメントに関心があります。それに到達するには、 isMediaNotificationメソッド に含まれているものを含むいくつかのチェックに合格する必要があります。はい、どうぞ:

  1. 通知には、通常のビューと大きなビューの両方が含まれている必要があります。
  2. 両方のビューの最上位レイアウトには、IDとしてcom.Android.internal.R.id.status_bar_latest_event_contentが必要です。
  3. 大きなレイアウトには、IDとしてcom.Android.internal.R.id.media_actionsを持つウィジェットが含まれている必要があります。

[〜#〜]方法[〜#〜]
最も問題となるのは、内部リソースで宣言されており、アプリケーションのレイアウトXMLからアクセスできないIDです。
2番目の問題は、通知で使用されるRemoteViewsがアプリケーション内のレイアウトリソースのIDであり、コードで構築できないことです。その結果、上記のすべてのチェックに合格するために必要なIDを持つレイアウトを追加することはできません。

ただし、Googleは必要に応じてaddViewメソッドとremoveAllViewsメソッドをRemoteViewsに追加し(これらはMediaStyle通知で使用されます)、非公開にするのを忘れていました。

したがって、最終的なアイデアは単純です。

  • googleによって定義された内部レイアウトに基づいて通知を作成します(2番目のチェックに合格するため)
  • removeAllViewsですべてを削除します
  • addViewを使用してカスタムレイアウトを追加します
  • ビッグビューの特殊なケース:カスタムレイアウト内の非表示ビューにmedia_actionsを含むGoogleによって定義されたレイアウトを追加します(3番目のチェックに合格するため)

欠点:

  • 未使用のビューを膨らませる(膨らませた直後に削除されます)
  • 複雑でより深いレイアウト階層

[〜#〜]ソリューション[〜#〜]
カスタムビッグビューには、IDとしてAndroid.R.id.emptyを含むFrameLayoutが含まれている必要があります。実際には、ここでは任意のIDを使用できます。コードで同じIDを参照していることを確認してください(以下を参照)。

// We need theese ids to use internal Android resources
int topId = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "Android");
int topBigLayout = Resources.getSystem().getIdentifier("notification_template_material_big_media_narrow", "layout", "Android");
int topSmallLayout = Resources.getSystem().getIdentifier("notification_template_material_media", "layout", "Android");

RemoteViews viewSmall = ...; // Create our custom view here
RemoteViews viewBig = ...; // Create our custom big view here

// This is invisible inner view - to have media_actions in hierarchy
RemoteViews innerTopView = new RemoteViews("Android", topBigLayout);
viewBig.addView(Android.R.id.empty, innerTopView);

// This should be on top - we need status_bar_latest_event_content as top layout
RemoteViews topBigView = new RemoteViews("Android", topBigLayout);
topBigView.removeAllViews(topId);
topBigView.addView(topId, viewBig);

// This should be on top - we need status_bar_latest_event_content as top layout
RemoteViews topSmallView = new RemoteViews("Android", topSmallLayout);
topSmallView.removeAllViews(topId);
topSmallView.addView(topId, viewSmall);

Notification.Builder builder = new Notification.Builder(this);

builder.setSmallIcon(R.drawable.ic_notification)
        .setTicker("Some text")
        .setColor(0xff000000) // The desired color!
        .setContent(topSmallView);

Notification n = builder.build();
n.bigContentView = topBigView;

// Use our notification "n" here as usual

トップレベルのnotification_template_material_big_media_narrowの代わりに別のレイアウトを使用して、大きなビューの高さを操作することができます。適切なものを検索します ここ notification_template_xxx.xmlファイルの中から。ただし、media_actionsを階層に入れることを忘れないでください。

6
Stanislav

最終的に、公式のマテリアルデザインに従う場合は 仕様

カスタム通知のテキストには常にスタイルリソースを使用してください

通知のカスタムレイアウトを使用する場合は、デフォルトの背景を上書きせずに、APIバージョンに応じてテキストスタイルを変更することを検討してください。これは、2つのリソーススタイルファイルを作成し、現在のAPIバージョンに従って使用することで実現できます。

values-v21/notify_styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <!-- according to official recommendation custom notifications should has the same text style as default one-->
  <style name="NotificationHeader" parent="@Android:style/TextAppearance.Material.Notification.Title" />
  <style name="NotificationContent" parent="@Android:style/TextAppearance.Material.Notification.Line2" />
</resources>

そして

values/notify_styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <!-- according to official recommendation custom notifications should has the same text style as default one-->
  <style name="NotificationHeader" parent="@Android:style/TextAppearance.StatusBar.EventContent.Title" />
  <style name="NotificationContent" parent="@Android:style/TextAppearance.StatusBar.EventContent" />
</resources>

これは、通知の正しい動作です。

この側面を直接制御したい場合は、次のことを行うことをお勧めします。

  • フォルダーlayout_message_notification.xml内にres/layout-v21の代替バージョンを作成します

  • 外側を変更して、この新しいバージョンを少し変更しますレイアウトの背景色

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/layout_messageNotification"
    Android:orientation="horizontal"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@Android:color/gray">
//...
3
bonnyz