Android自定义Notification并没有那么简单
背景
最近需要实现一个自定义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并没有那么简单的更多相关文章
- android自定义Notification通知栏实例
项目有个需求,需要在发送Notification的时候动态给定url的图片.大概思路如下:自己定义一个Notification的布局文件,这样能够很方便设置View的属性. 首先加载网络图片,使用Bi ...
- Android: 自定义Tab样式,一种简单的方式。
之前看到过论坛里已经有人发过自定义Tab样式的帖子,感觉有些复杂了,这里分享个简单的方法. 1.制作4个9patch的tab样式,可参考android默认的资源 tab_unselected.9.pn ...
- 简单说说Android自定义view学习推荐的方式
这几天比较受关注,挺开心的,嘿嘿. 这里给大家总结一下学习自定义view的一些技巧. 以后写自定义view可能不会写博客了,但是可以开源的我会把源码丢到github上我的地址:https://git ...
- Android自定义view(一):制作一个最最最简单的自定义view
转载:https://blog.csdn.net/wsyizmao/article/details/78491422 浅谈安卓自定义view(一):制作一个最最最简单的自定义view 对于安卓程序员来 ...
- Android -- 系统和自定义Notification
Notification是一种让你的应用程序在不使用Activity的情况下警示用户,Notification是看不见的程序组件警示用户有需要注意的事件发生的最好途径. 作为UI部分,Notifica ...
- android的几种“通知”方式简单实现(Notification&NotificationManager)
关于通知Notification相信大家都不陌生了,平时上QQ的时候有消息来了或者有收到了短信,手机顶部就会显示有新消息什么的,就类似这种.今天就稍微记录下几种Notification的用法.3.0以 ...
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
在android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...
- Android 中Notification的运用
Notification在手机的运用中是很常见的,比如我们收到一个短信,在我们的通知栏就会显示一个消息的图标用来提示我们,这种我们就可以用Notification来实现.他有很多的用法,比如类似消息的 ...
- Android开发——Notification通知的使用及NotificationCopat.Builder常用设置API
想要看全部设置的请看这一篇 [转]NotificationCopat.Builder全部设置 常用设置: 设置属性 说明 setAutoCancel(boolean autocancel) 设置点击信 ...
随机推荐
- service httpd restart失败解决方法(小记)
1.首先查看错误日志 /var/log/message看看具体问题.如果一时难以判定直接使用下面一招 2.直接中断http服务,killall -9 httpd, 然后重启http,service ...
- javascript 与 java
- EasyPHP的Apache报错
今天安装了最新版本的软件:EasyPHP-DevServer-14.1VC11-install.exe 启动报错: 打开Cport软件: 可见80端口被系统占用,导致Apache不能启动. (1)手动 ...
- 【POJ1113】Wall(凸包)
[题目] Description Once upon a time there was a greedy King who ordered his chief Architect to build a ...
- 查看SQL Server数据库中各个表和视图的索引所占的空间大小
;with cte as ( (select t.name as TableName,i.name as IndexName, sum(row_count)as row_count, SUM (s.u ...
- MEMS Gyroscope Technology
InvenSense®Technology Overview Our technology is comprised of five coreelements: our patented Nasiri ...
- Android开源项目发现--- 工具类网络相关篇(持续更新)
1. Asynchronous Http Client for Android Android异步Http请求 项目地址:https://github.com/loopj/android-async- ...
- hdu 1042 N!(高精度乘法 + 缩进)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1042 题目大意:求n!, n 的上限是10000. 解题思路:高精度乘法 , 因为数据量比较大, 所以 ...
- Linux学习笔记7——linux中的静态库和动态库
一.静态库的编译 静态库的编译过程如下: 1.编译成目标文件 这里有一个可选项-static,调用格式:gcc -c -static 代码文件名.c 2.归档成静态库 A.归档的工具是ar工具,使用a ...
- phpmyadmin万能密码
影响版本:2.11.3 / 2.11.4 利用方法:用户名处写入‘localhost’@'@”则登录成功. (注意全部是英文标点符号,最后一个为英文双引号)