设置Android通知栏Notification的字体/图标颜色随背景色变化而变化

设置通知栏中的字体/按钮颜色随系统下拉菜单背景色变化而变化

本篇内容为:Android端APP在下栏菜单中发出通知(Notification)时,在设置该通知背景透明的前提下,如何使得通知中的字体颜色和图标在不同颜色的下栏菜单中均能保持较高的对比度。从中受益的两篇文章分别是Android 自定义通知Notification 适配不同背景颜色通知栏设置系统字体颜色.


起因

常见的方式是为通知加入背景色。有背景色的通知栏虽然保证了文字和图标的对比度,但是不能完美融入不同颜色的下拉菜单中。网易云音乐做得到了背景色透明,且通知栏字色也始终具有较高的对比度,但按钮图标只有一套,在下拉菜单的背景色和图标色相近时会导致按钮不够明显~显示效果如图:

这里写图片描述

如何使得通知中的字体颜色和图标颜色自适应不同的手机主题呢?文章开篇给出了参考的两篇文章,分别对应着两种解决方案,这里从简描述,有需要的童鞋可点击链接查看详细内容。我重点讲述取之长,补之短的方案三。

方案一

原理

因为系统通知的文字颜色会随着(不同主题的)下拉菜单的背景色变化而变化,该方法设置自定义通知的文字颜色与系统通知的文字颜色相同,从而达到保证文字对比度的目的。

步骤

这个方案给出了低于5.0的Android版本和高于5.0的Android版本的不同的方案,简而言之就是:在低于5.0的Android版本中,在通知的布局文件(.xml)中的题目Title和简介Introduction中,分别添加如下的一行语句:

...
    <TextView>
        ...
        android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
        ...
    </TextView>

在高于5.0的版本中,在通知的布局文件中表示Title的<TextView>中添加一行语句:

...
    <TextView>
        ...
        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
        ...
    </TextView>

在通知的布局文件中表示简介Introduction的<TextView>中添加一行语句:

...
    <TextView>
        ...
        android:textAppearance="@android:style/TextAppearance.Material.Notification.Line2"
        ...
    </TextView>

即可实现自定义通知的文字颜色与系统通知的文字颜色相同。

方案一的不足

但是这种方案有两个不足:
低于5.0版本的方案Title和Introduction同色(通常都为灰色),如果要求这两项有不同对比度,则该方案欠佳;
高于5.0版本的方案,其限制条件“高于5.0版本”就是不足。

方案二

原理

方案二通过遍历系统通知的viewGroup,获取系统通知中的字体颜色;继而对字体颜色进行判定,是偏黑色主题还是偏浅色主题;最终根据返回的主题颜色,改变自定义通知中的字体颜色。

步骤

代码可读性较高,直接上源码。拷贝自此,根据实际项目有略微差异。

public boolean isDarkNotificationTheme() {
    return !isSimilarColor(Color.BLACK,getNotificationColor(musicService.getApplicationContext()));
}


public static int getNotificationColor(Context context) {
    NotificationCompat.Builder builder=new NotificationCompat.Builder(context);
    Notification notification=builder.build();
    int layoutId=notification.contentView.getLayoutId();
    ViewGroup viewGroup= (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
    if (viewGroup.findViewById(android.R.id.title)!=null) {
        return ((TextView) viewGroup.findViewById(android.R.id.title)).getCurrentTextColor();
    }
    return findColor(viewGroup);
}


private boolean isSimilarColor(int baseColor, int color) {
    int simpleBaseColor=baseColor|0xff000000;
    int simpleColor=color|0xff000000;
    int baseRed=Color.red(simpleBaseColor)-Color.red(simpleColor);
    int baseGreen=Color.green(simpleBaseColor)-Color.green(simpleColor);
    int baseBlue=Color.blue(simpleBaseColor)-Color.blue(simpleColor);
    double value=Math.sqrt(baseRed*baseRed+baseGreen*baseGreen+baseBlue*baseBlue);
    if (value<180.0) {
        return true;
    }
    return false;
}


private static int findColor(ViewGroup viewGroupSource) {
    int color=Color.TRANSPARENT;
    LinkedList<ViewGroup> viewGroups=new LinkedList<>();
    viewGroups.add(viewGroupSource);
    while (viewGroups.size()>0) {
        ViewGroup viewGroup1=viewGroups.getFirst();
        for (int i = 0; i < viewGroup1.getChildCount(); i++) {
            if (viewGroup1.getChildAt(i) instanceof ViewGroup) {
                viewGroups.add((ViewGroup) viewGroup1.getChildAt(i));
            }
            else if (viewGroup1.getChildAt(i) instanceof TextView) {
                if (((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor()!=-1) {
                    color=((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor();
                }
            }
        }
        viewGroups.remove(viewGroup1);
    }
    return color;
}

最后通过

contentView.setInt(R.id.share_content, "setTextColor", NotificationUtils.isDarkNotificationTheme()==true?Color.WHITE:Color.BLACK);

实现颜色替换的功能。

优劣

优势:可自定义通知中Title和Introduction的字体颜色;
劣势:好像依旧无法更换通知中的按钮。

此外,我尝试通过返回的isDarkNotificationTheme()的具体结果,通过以下代码更改通知中字体的颜色和图标:

private View view;
private TextView notificationTitleTextView;
private TextView notificationSubtitleTextView;
private ImageView notificationPlayorpauseImageView;

View view = LayoutInflater.from(MusicPlayer.this).inflate(R.layout.music_notification, null);
notificationTitleTextView = (TextView) view.findViewById(R.id.notification_title_textView);
notificationsubTitleTextView = (TextView) view.findViewById(R.id.notification_subtitle_textView);
notificationPlayorpauseImageView = (ImageView) view.findViewById(R.id.notification_subtitle_textView);

if(isDarkNotificationTheme()){
    notificationTitleTextView.setTextColor(getResources().getColor(R.color.black));
    notificationsubtitleTextView.setTextColor(getResources().getColor(R.color.gray));
    notificationPlayorpauseImageView.setImageResource(R.mipmap.playOrPauseImageView);
}else{
//如上,替换成不同的颜色/图标
}

但是发现在通知中并没有起效果,也就是说这种方式并不适用于通知。

方案三

方案三包括两部分内容,其一是针对方案一的一点小改动,以符合无视Android版本都能进行适配的要求;但并不能解决无法更换图标的问题。其二是结合方案一和方案二,实现最终的文字颜色/图标随手机主题更换后背景色变化而变化。

方式一:

留心方案一中高于Android 5.0版本的方法:虽然

“@android:style/TextAppearance.Material.Notification.Line2”

要求的最低版本为API 21,但

“@android:style/TextAppearance.Material.Notification.Title”

要求的最低版本为仅为API 9. 考虑到现在市面上几乎全部Android手机的Android版本的API都高于API 9, 可在Title的<TextView>中设置

android:textAppearance=”@android:style/TextAppearance.Material.Notification.Title”

在Introduction的<TextView>中设置

android:textAppearance=”@style/TextAppearance.StatusBar.EventContent”

即可实现保持Title和Introduction高对比度的前提下,Title和Introduction具有不同的灰度颜色(Title为黑/白,Introduction为不同程度的灰色)。

改进后的优劣:

优势:简单方便;更换深/浅色主题后自定义通知的字体颜色立即做响应改变。
劣势:文字颜色不能自定义;不能改变图标颜色。

方式二

1)因为方案一有简单、背景变化时文字颜色响应迅速的特点,在通知的字体颜色上采用方式一;
2)利用方案二,获知当前主题是深色还是浅色,之后根据主题色采用不同颜色的图标。

步骤一

在通知的布局文件中表示Title的<TextView>中添加一行语句:

...
    <TextView>
        ...
        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
        ...
    </TextView>

在通知的布局文件中表示简介Introduction的<TextView>中添加一行语句:

...
    <TextView>
        ...
        android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
        ...
    </TextView>
步骤二

首先使用方案二,获取到当前主题色是深色还是浅色:


public boolean isDarkNotificationTheme() {
    return !isSimilarColor(Color.BLACK,getNotificationColor(musicService.getApplicationContext()));
}


public static int getNotificationColor(Context context) {
    NotificationCompat.Builder builder=new NotificationCompat.Builder(context);
    notification=builder.build();
    int layoutId=notification.contentView.getLayoutId();
    ViewGroup viewGroup= (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
    if (viewGroup.findViewById(android.R.id.title)!=null) {
        return ((TextView) viewGroup.findViewById(android.R.id.title)).getCurrentTextColor();
    }
    return findColor(viewGroup);
}


private boolean isSimilarColor(int baseColor, int color) {
    int simpleBaseColor=baseColor|0xff000000;
    int simpleColor=color|0xff000000;
    int baseRed=Color.red(simpleBaseColor)-Color.red(simpleColor);
    int baseGreen=Color.green(simpleBaseColor)-Color.green(simpleColor);
    int baseBlue=Color.blue(simpleBaseColor)-Color.blue(simpleColor);
    double value=Math.sqrt(baseRed*baseRed+baseGreen*baseGreen+baseBlue*baseBlue);
    if (value<180.0) {
        return true;
    }
    return false;
}


private static int findColor(ViewGroup viewGroupSource) {
    int color=Color.TRANSPARENT;
    LinkedList<ViewGroup> viewGroups=new LinkedList<>();
    viewGroups.add(viewGroupSource);
    while (viewGroups.size()>0) {
        ViewGroup viewGroup1=viewGroups.getFirst();
        for (int i = 0; i < viewGroup1.getChildCount(); i++) {
            if (viewGroup1.getChildAt(i) instanceof ViewGroup) {
                viewGroups.add((ViewGroup) viewGroup1.getChildAt(i));
            }
            else if (viewGroup1.getChildAt(i) instanceof TextView) {
                if (((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor()!=-1) {
                    color=((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor();
                }
            }
        }
        viewGroups.remove(viewGroup1);
    }
    return color;
}

之后实现更换通知中图标的函数,函数中调用Android自带的更新通知中文字和图标的方法setImageViewResource:

public void setNotificationColor(){
    if(isDarkNotificationTheme()){
        setImageViewResource(R.id.notification_play_pause, R.mipmap.ic_audio_playing_night);
        setImageViewResource(R.id.notification_img_next, R.mipmap.ic_audio_next_night);
    }else {
        setImageViewResource(R.id.notification_play_pause, R.mipmap.ic_audio_playing);
        setImageViewResource(R.id.notification_img_next, R.mipmap.ic_audio_next);
    }
    refreshView();
}

// private Notification notification builder.build();
// public static NotificationManager notificationManager = (NotificationManager)service.getSystemService(Context.NOTIFICATION_SERVICE);
private void refreshView(){
    if(notification != null){
        notificationManager.notify(NOTIFICATION_ID, notification);
}

即大功告成。如果想自己定义通知中Title和Introduction的字体颜色,在setNotificationColor()方法的if语句中中添加

setTextColor(R.id.notification_title_textview, getResources().getColor(R.color.title_color));
setTextColor(R.id.notification_subtitle_textview, getResources().getColor(R.color.title_color));

最终效果如图中最顶端的通知,分别展示在深色主题下和浅色主题下的显示效果:
这里写图片描述

备注:其中R.mipmap.xxx是在工程中的android/src/main/res/mipmap文件夹中自行添加的图标;R.color.xxxxx是在工程中的android/src/main/res/values/color.xml中自行定义的颜色。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android通知是一种用于显示应用程序通知的用户界面元素。它可以在屏幕的顶部或底部显示,并且可以包含文本、图像、声音和其他交互元素。通知可以帮助用户及时了解应用程序的状态和事件,例如新消息、更新、提醒和警告等。开发人员可以使用Android SDK提供的通知API来创建和管理通知,以便更好地与用户进行交互。 ### 回答2: Android 通知是一种提供给用户显示有关当前状态和行动的信息的方式,以便用户可以及时地采取必要的行动。通知可以显示来自应用程序和系统的通知消息,例如电子邮件、信息和其他事件,可以让用户在不离开当前应用的情况下对这些消息进行响应。 在通知中,每个通知都包含一个图标、标题、简短的消息文本和通知时间。用户可以从通知中直接打开应用程序或查看通知的详细信息。通知还可以显示多个通知,按照时间顺序进行排序。 开发人员可以使用 Android SDK 提供的 Notification 类来创建自定义通知。可以设置通知图标、文本、声音、震动和延迟时间等属性。还可以指定通知的优先级,以便系统在有限的屏幕空间中为用户先显示最重要的通知通知还可以与 PendingIntent 实例相关联,以便在用户单击通知时执行特定的操作,例如打开应用程序,启动活动或显示通知详细信息的专用活动。 总之,Android 通知是一种非常有用的功能,可以让用户及时了解应用程序和系统中的重要事件,并采取及时的行动。开发人员可以使用通知来实现更好的用户体验。 ### 回答3: Android 通知是一种非常有用的功能,它可以让你的应用程序以一种全新的方式与用户进行交互。在 Android 应用程序中,通知是一种特殊的 UI 元素,它显示在屏幕的顶部,并显示当前状态、事件或提示。通知通常包含一组小图标,可以展开或折叠以显示更多详细信息。 Android 通知有许多不同的用途,例如提醒用户新的消息、电子邮件、电话、提醒等等。发送通知的应用程序无需与用户保持连接,这使得通知非常适合后台服务或其他形式的低功耗通信。通知还允许用户直接从通知菜单中操作应用程序。例如,当用户收到新的电子邮件时,他们可以在通知中选择该电子邮件并立即查看其内容,而无需打开电子邮件应用程序。 Android 通知的另一个优点是它的可定制性。可以轻松地修改通知的外观、行为和内容,以满足不同应用程序的需求和设计要求。您可以为通知添加各种元素,如纯文本、小图标、大图标、进度指示器、按钮等等。这样,您可以轻松地创造与您的品牌和应用程序设计语言保持一致的通知。 在实现通知之前,您需要确保该应用程序已获得了通知权限。如果您的应用程序需要通知用户任何内容,则必须获得 Android 手机上的通知权限。可以在应用程序设置中找到此选项。 虽然 Android 通知很有用,但在某些情况下,它们可能会变得令人分心。因此,应该仔细考虑应用程序通知的数量和类型,以确保用户不会感到困扰。通知还可以消耗设备电池,因此也应考虑优化应用程序以最小化资源消耗。 Android 通知作为 Android 应用程序非常重要的一部分,可以帮助您在应用程序和用户之间建立更紧密的联系,并提供有关应用程序状态、事件和提示的有用信息。通过努力优化您的应用程序通知,您可以确保用户感到受到了关注,并且同时不会让他们感到困扰。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值