背景

最近需要实现一个自定义Notification的功能。网上找了找代码,解决方案就是通过RemoteViews来实现。但是在实现过程中遇到不少问题,网上也没有很好的文章描述这些问题,所以在这里做个总结,希望大家能少走点弯路。

实现

RemoteViews 自定义View

这是最基础的知识点,虽然做过自定义通知的应该都清楚,但我觉得还是有必要带一下。它主要被用于AppWidget和Notification,它描述一个在其它进程中显示的View。以下是例子代码。从中我们可以看到RemoteViews提供了一些方法来改变它的子View的值,如设置TextView的文字等。

RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.view_notification_type_0);
remoteViews.setTextViewText(R.id.title_tv, title);
remoteViews.setTextViewText(R.id.content_tv, content);
remoteViews.setTextViewText(R.id.time_tv, getTime());
remoteViews.setImageViewResource(R.id.icon_iv, R.drawable.logo);
remoteViews.setInt(R.id.close_iv, "setColorFilter", getIconColor());
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(NOTICE_ID_KEY, NOTICE_ID_TYPE_0);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
int requestCode = (int) SystemClock.uptimeMillis();
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.notice_view_type_0, pendingIntent);
int requestCode1 = (int) SystemClock.uptimeMillis();
Intent intent1 = new Intent(ACTION_CLOSE_NOTICE);
intent1.putExtra(NOTICE_ID_KEY, NOTICE_ID_TYPE_0);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, requestCode1, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.close_iv, pendingIntent1);

这里有几点需要注意的。

setInt

这个方法被用来调用子View中需要一个Int型参数的方法。如下面这句代码,调用了id为close_iv的setColorFilter方法,参数为getIconColor()的返回值。

remoteViews.setInt(R.id.close_iv, "setColorFilter", getIconColor());

设置不同区域的点击PendingIntent

默认的Notification只能通过setContentIntent设置整体的点击事件。不过通过RemoteViews我们可以设置不同地方不同的点击事件,当然这里的事件指的是PendingIntent。如下,设置了点击R.id.notice_view_type_0打开一个Activity,而点击R.id.close_iv会发出一个广播,可以通过这个广播的广播接收器来做一些事情,如这里是关闭当前的Notification。另外还可以打开一个Service。

PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.notice_view_type_0, pendingIntent);
int requestCode1 = (int) SystemClock.uptimeMillis();
Intent intent1 = new Intent(ACTION_CLOSE_NOTICE);
intent1.putExtra(NOTICE_ID_KEY, NOTICE_ID_TYPE_0);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, requestCode1, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.close_iv, pendingIntent1);

设置通知的自定义View

以上我们得到了自定义的RemoteViews。通过下面这段代码就能生成自定义View的Notification,注意这里使用了setContent()方法。这是网上自定义Notification都会使用的方法。

Notification notification = new NotificationCompat.Builder(context).setContent(remoteViews).build();

但是它会有一个问题。

通过setContent()方法获得的Notification是定高的。如果View的高度比默认高度要大的话,就有一部分显示不出来。如下图

默认情况下通知高度为64dp,当然Rom不同可能会有些区别。一般文字在小于两行的情况下都是可以显示。

那么如何做到wrap_content。需要使用一些黑科技。如下:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
if(android.os.Build.VERSION.SDK_INT >= 16) {
notification = builder.build();
notification.bigContentView = remoteViews;
}
notification.contentView = remoteViews;

为了理解以上代码,我们需要明确一个我们很容易忽略的问题,那就是通知是可以展开和收起的。请看以下两张图片。同样是网易云音乐的通知,图一比图二要大一些。其实图一展示的是网易云音乐通知的展开状态,使用两个手指上滑就可以缩起,也就是图二。

在上面的代码中我们分别设置了bigContentView 这是展开的自定义视图,而contentView则是收起时的视图。

注意bigContentView是在sdk16时引入的,所以需要判断一下。如果小于sdk16则只能定高了。

注意bigContentView 的最大高度是256dp

注意bigContentView和contentView的设置不能调转顺序,亲测这样会让contentView不显示。

另外需要注意某些Rom可能不支持展开收起通知,在设置了BigContentView之后就只显示展开的视图,而默认情况下只展示收起视图。如魅族的FlyMe,其它Rom并没有测试,如果读者知道可以分享一下。

背景色适配

不同Rom的通知背景色是不同的,所以在UI上需要注意。 主要分为两种情况。

  • 背景色为有透明度的黑色,如MiUi、FlyMe。
  • 背景色为白色,如原生的5.0之后的Rom、华为部分Rom。

主要有两种方案。

固定背景色

也就是设置一个固定的背景色,文字和icon颜色都可以固定。如下图。这有一个缺点,我们在图中也看到了,那就是某些Rom的Notification会有一个左右的padding,如MIUI的就特别明显,如果固定背景色就会很难看。所以这种方法虽然简答,但是不建议使用。

透明背景色

另一种方法就是让背景透明。那么文字和icon的颜色怎么办呢?很简单,跟随系统的Notification中文字的样式。如下设置了TextView的style为默认通知中info的样式。其它相关Style包括TextAppearance.StatusBar.EventContent.Line2、TextAppearance.StatusBar.EventContent.Info等。

        <TextView
android:id="@+id/content_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
tools:text="41个同校小伙伴参与讨论"
android:layout_marginTop="4dp"
android:singleLine="true"/>

需要注意的一点是Android5.0之后使用了不同的Style名表示通知样式。 我们需要创建一个layout-v21文件夹,并新建一个在5.0之后使用的自定义通知样式。如下同样是设置TextView的style为Info的样式,但我们使用的是style是@android:style/TextAppearance.Material.Notification.Info。

<TextView
android:id="@+id/content_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="9sp"
android:textAppearance="@android:style/TextAppearance.Material.Notification.Info"
tools:text="41个同校小伙伴参与讨论"
android:layout_marginTop="4dp"
android:singleLine="true"/>

另外如果自定义view中有Icon,那么Icon的颜色也需要适应背景,可以选择一个灰色,如#999999,原生安卓黑色和白色的文字内容颜色都为该值。

或者根据不同的背景色设置不同的颜色,通过上面提到的setInt方法。ImageView的setColorFilter方法可以设置图案颜色为某种纯色。但是目前我还没有找到很好的方法获取默认通知的背景色,如果读者找到了望告知。

remoteViews.setInt(R.id.close_iv, "setColorFilter", getIconColor());

最终效果

总结

以上即为我在自定义Notification中遇到的一些问题以及解决方案。目前还有两点有待进一步补充和完善。

  • 获取默认通知背景色,或者使图标颜色与背景色适配的方案。
  • 不支持Notification展开收起的Rom,目前知道的仅有FlyMe。

示例代码地址

https://github.com/beautifulSoup/CNotification

Android自定义Notification并没有那么简单的更多相关文章

  1. android自定义Notification通知栏实例

    项目有个需求,需要在发送Notification的时候动态给定url的图片.大概思路如下:自己定义一个Notification的布局文件,这样能够很方便设置View的属性. 首先加载网络图片,使用Bi ...

  2. Android: 自定义Tab样式,一种简单的方式。

    之前看到过论坛里已经有人发过自定义Tab样式的帖子,感觉有些复杂了,这里分享个简单的方法. 1.制作4个9patch的tab样式,可参考android默认的资源 tab_unselected.9.pn ...

  3. 简单说说Android自定义view学习推荐的方式

    这几天比较受关注,挺开心的,嘿嘿. 这里给大家总结一下学习自定义view的一些技巧.  以后写自定义view可能不会写博客了,但是可以开源的我会把源码丢到github上我的地址:https://git ...

  4. Android自定义view(一):制作一个最最最简单的自定义view

    转载:https://blog.csdn.net/wsyizmao/article/details/78491422 浅谈安卓自定义view(一):制作一个最最最简单的自定义view 对于安卓程序员来 ...

  5. Android -- 系统和自定义Notification

    Notification是一种让你的应用程序在不使用Activity的情况下警示用户,Notification是看不见的程序组件警示用户有需要注意的事件发生的最好途径. 作为UI部分,Notifica ...

  6. android的几种“通知”方式简单实现(Notification&NotificationManager)

    关于通知Notification相信大家都不陌生了,平时上QQ的时候有消息来了或者有收到了短信,手机顶部就会显示有新消息什么的,就类似这种.今天就稍微记录下几种Notification的用法.3.0以 ...

  7. Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)

    在android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...

  8. Android 中Notification的运用

    Notification在手机的运用中是很常见的,比如我们收到一个短信,在我们的通知栏就会显示一个消息的图标用来提示我们,这种我们就可以用Notification来实现.他有很多的用法,比如类似消息的 ...

  9. Android开发——Notification通知的使用及NotificationCopat.Builder常用设置API

    想要看全部设置的请看这一篇 [转]NotificationCopat.Builder全部设置 常用设置: 设置属性 说明 setAutoCancel(boolean autocancel) 设置点击信 ...

随机推荐

  1. Linux内核监控模块-2-系统调用表地址的获取(Linux内核版本3.13)

    那么在Linux内核2.6之后,不能直接导出sys_call_table的地址后,我们要如何获得系统调用表的地址,从而实现系统调用的截获呢. 先贴上我实现好的代码,然后再来讲解吧. modu.c #i ...

  2. rest开发

    http://www.mkyong.com/webservices/jax-rs/download-json-from-jax-rs-with-jaxb-resteasy/ http://blog.j ...

  3. MFC窗口风格 WS_style/WS_EX_style(超详细)

    窗口风格(Window style) WS_BORDER   有边框窗口 WS_CAPTION   必须和WS_BORDER风格配合,但不能与WS_DLGFRAME风格一起使用.指示窗口包含标题要部分 ...

  4. LINUX6.3下RHCS的安装文档

    LINUX6.3下RHCS的安装及集群的配置文档 环境: 目前要给华为E6000系列的两个刀片安装RHCS,每一块刀片有两个业务网口和一个管理网口,但是看不见不物理网卡,而是连接到刀片自身携带的一个交 ...

  5. centos6.5 设置静态ip地址

    vim /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 #描述网卡对应的设备别名,例如ifcfg-eth0的文件中它为eth0BOOTPRO ...

  6. Linux Shell编程(27)——子shell

    运行一个shell脚本时会启动另一个命令解释器. 就好像你的命令是在命令行提示下被解释的一样, 类似于批处理文件里的一系列命令.每个shell脚本有效地运行在父shell(parent shell)的 ...

  7. soundtouch源码分析__based on csdn :

    1. soundtouch介绍和相关资源 The SoundTouch Library Copyright © Olli Parviainen 2001-2014 SoundTouch is an o ...

  8. 【转】Ubuntu14.04搭建安装svnserver

    原文网址:http://www.cnblogs.com/blfshiye/p/5168028.html 前两天,公司准备搭建一个svnserver,供大家使用.于是.就先装了一个Ubuntu系统,然后 ...

  9. sql server知道触发器名如何查看里面代码

    以sqlserver2008为例,可以写代码查看,也可以通过SQL Server Manager Studio工具的树形列表查看. 一.代码查看: 直接在SQL Server Manager Stud ...

  10. 常用myeclipse的快捷键,对菜鸟超有用的

    1. ctrl + h ,这个键超有用的,可以搜索当前项目的整个文件,并锁定到改文件的 具体位置.如图: 2.ctrl + o,在java文件内,搜索该文件下的所有方法.如图: ctrl + d ,删 ...