Android自定义通知样式适配

今天是端午节,祝大家节日快乐


这篇文章着实酝酿了许久,一直懒得写。网上关于通知栏样式适配的文章很多,但还不够完美,这也是我写这篇文章的动力所在。

温故而知新


Android通知有两种,默认通知与自定义通知。默认通知简单调用系统接口就能实现,如下:

发送默认通知
默认通知效果

自定义通知就稍微麻烦一些,需要定义一个layout文件,使用RemoteViews加载它并设置一些点击事件,再设置到builder,如下:

自定义通知代码
自定义通知效果

这个通知很简单,就是两行文本加上一个按钮,按钮具有单独的点击事件,点击后跳转到AnotherActivity。

注意:smallIcon对于自定义通知和默认通知都是必须的,否则通知显示不出来。道理很简单,smallIcon需要在状态栏上显示,不设置怎么行。在5.0及以上,smallIcon必须符合Material Design风格,即白色内容,透明背景。不然系统会使用默认的图片替换。具体可参考Android通知栏微技巧,那些你所没关注过的小细节 标签: android通知通知栏微技巧。后面我会有一篇更详细的文章来介绍这个。contentIntent对于2.3及以下的系统是必须的,否则发送通知时会抛异常。道理也很简单,Android 2.3及以下系统不支持给自定义通知上的元素绑定单独的点击事件,因此必须设置整个通知的点击事件。

为什么要进行样式适配?


默认通知不存在样式适配的问题,因为默认通知的布局、颜色、背景什么的都是系统的,系统总会正确的显示默认通知。但自定义通知就不一样了,自定义通知的布局完全由我们自己掌控,我们可以为元素设置任何背景、颜色。那么,问题来了。Android通知栏的背景各种各样,不同的ROM有不同的背景,白色、黑色、透明等。不同的Android版本通知栏背景也不一样,一旦我们为自定义通知上的元素设置了特定背景或颜色,就肯定会带来兼容性问题(主要是文本啦)。这样的应用一大把,贴个图大家就明白了:

未适配的自定义通知

怎么适配?


适配的方式大概有两种,一种简单粗暴:为自定义通知设置固定的背景(上图中的360卫士就这么干的),比如黑色。那么内容自然就是白色或近似白色。这样,在所有的手机上都能正常显示,不会出现在黑色背景通知栏上显示良好,到了白色背景通知栏上就几乎啥也看不见。使用这种方案的应用太多了。我个人很不推崇这种方式,这样会使得自定义通知在将近一半的手机上显示得很突兀,和系统的通知栏不够沉浸,影响整体美观。另一种方案就稍微合理一些:通过读取系统的通知栏样式文件,获取到title和content的颜色,进而将这个颜色设置到自定义通知上。读取通知栏样式文件本身有兼容性问题,不同Android版本的样式文件有变,具体可参考这篇博客 通知栏设置系统字体颜色 ,这种方式也不是在所有手机上生效,实际测试发现,还是有小部分机型没法读取或是读取到的是错误的。拿到title和content的颜色后,还可以通过算法(后面细说)判断这个颜色是近似白色还是近似黑色,进而能判断出通知栏的背景是近似黑色还是近似白色,这样就能根据不同的通知栏背景加载不同的自定义通知布局。进而做到良好的适配。

更好的适配


现在切入主题,谈谈如何来更好的适配自定义通知。有过锁屏开发经验的人应该知道,如果你的应用有读取系统通知栏的权限,那么每当应用程序发出一个通知,你的应用都会收到对应的notification对象,这个时候,我们一般会执行以下操作:

获取并展示app通知

调用addView之后,应用程序的通知就会显示在我们的应用里。显然,上面的代码并没有对apply返回的notificationItemLayout做任何其他操作,但确实这个View显示出来时就是样式良好的,可见,notificationItemLayout本身就是带有样式的,即便是默认通知。那么方案来了!我们先构造一个默认通知:

获取通知栏title的颜色

通知并不发送出去,只是用来获取通知栏title的颜色,如果你还想获取content的颜色,抱歉,不能通过查找android.R.id.text来获取,这个字段是访问不到的。可通过反射获取,更好的办法是先预先设置一个content,然后遍历viewGoup根据content内容找到对应的TextView再获取颜色。

拿到颜色后,可根据算法判断这个颜色是近似白色还是近似黑色,我们使用黑色作为基准色,使用方差来计算这个颜色是否近似黑色:

比较两个颜色是否近似

baseColor传入Color.BLACK,color传入刚刚获取到的title的颜色,根据我实测,阈值为180.0较为合理。上述方法返回true,即表示title的颜色近似黑色,也就是说通知栏背景近似白色。

额,经验丰富的同学应该已经洞察到第二段代码存在的兼容性问题了:根据android.R.id.title去找到title对应的TextView是不靠谱的,因为有些ROM厂商会把id改掉,导致找到的title为空。

同时还有另外一个问题:使用上述方法,Activity不能继承自AppCompatActivity(实测5.0以下机型可以,5.0及以上机型不行),大致的原因是默认通知布局文件中的ImageView(largeIcon和smallIcon)被替换成了AppCompatImageView,而在5.0及以上系统中,AppCompatImageView的setBackgroundResource(int)未被标记为RemotableViewMethod,导致apply时抛异常。

为了解决这两个问题,我们改进getNotificationColor方法:

改进后的方法

在getNotificationColorInternal中,设置一个默认的title文本,如果根据id找不到title,则遍历notificationRoot根据设置的title文本找到title:

兼容厂商改id

在getNotificationColorCompat中,我们先构造一个默认通知,获取到默认通知的布局文件id,并将布局加载到notificationRoot,此时,如果根据id找不到title,显然设置默认title的办法已经失效了。如何从notificationRoot中找到title是个问题。我的解决办法是:反正都已经拿到notificationRoot了,不如就遍历它,先找到其中的所有TextView,取字体最大的TextView作为title(这是合理的,因为默认通知中最多也就4个TextView,分别是title、content、info、when,title肯定是字体最大,最显眼的),并返回其颜色:

兼容AppCompatActivity

实际测试


拿到了通知栏背景的颜色后,我们就可以加载不同样式的布局,达到适配的目的。代码如下:

适配代码

效果:

Android 4.4黑色背景的通知栏


坚果手机白色版白色通知栏

好了,我的第一篇技术博客到此为止,大家假期玩得Happy!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,614评论 4 59
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 《风》 我是一阵永不停歇的风 可能有些粗犷 因为我会 吹掉月亮的一层伪装 吹起街角的一缕彷徨 你需要知道 即...
    时间化成了烟阅读 185评论 0 2
  • 一、基本语法 1.1 关键字 1.2 标识符 1.3 变 量 1.3.1、变量的概念: 1.3.2、变量的分类 ...
    鸩羽千夜92阅读 727评论 0 1