隐藏

Android 消息通知栏用法详解(一)

发布:2020/11/18 13:47:13作者:管理员 来源:本站 浏览次数:1382

Android 消息通知栏用法详解(二) 适配8.0

通知(Notification) 是Android 系统比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息的时,而该应用程序又处于后台,就可以借助通知来实现。比如微信弹窗。通过这篇文章,我们将学习到

  • Notification 的基本用法
  • Notification 声音、优先级、多文字和大图片的显示
  • Notification 高级玩法
  • 自定义 Notification 的布局

官网 Nitification 资料

一、基本用法

通知可以在 广播、activity 或者 service 去创建,不过在 activity 创建得比较少,一般都是应用在后台了,才需要去弄,不过我们是demo,所以写哪都没关系。

创建通知的基本步骤如下:

  1. 使用getSystemService 拿到 NotificationManager 的管理类
  2. 使用NotificationCompat 设置标题、内容、图片等
  3. 最后调用 NotificationManager 的 notify() 调出通知栏

上面中,为什么要使用 NotificationCompat 呢,因为Android系统的每一个版本都会对通知这部分功能进行或多或少的修改,API 比较不稳定,所以这里使用 v4 的包去兼容,当然,如果你使用 androidx,也就没啥问题了。
所以,一个简单的通知实例如下 :

以下代码建议在8.0之下运行,8.0以上,请参考下一篇文章

首先创建 NotificationManager

mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
  • 1
 mBuilder = new NotificationCompat.Builder(this)
          .setContentTitle("这是标题")
          .setContentText("我是内容,我是demo")
          .setWhen(System.currentTimeMillis())
          .setSmallIcon(R.mipmap.ic_launcher)
          .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
 
  //通过 builder.build() 拿到 notification
  mNotificationManager.notify(1, mBuilder.build()); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

解释如下:

  • setContentTitle 为设置标题
  • setContentText 为正文内容
  • setWhen 为通知创建时间,以 ms 为单位
  • setSmallIcon 通知的小图标,注意只能使用 纯 alpha 图层的图片进行设置
  • setLargeIcon 通知栏的大图标

都设置完成之后,只要使用 nofity() 即可,其中,第一个参数为 id,后面用来取消通知的。所以随便填一个数字即可,效果如下。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200327070642163.png

可以看到,小图标是灰色的。当然了,google 要求是 alpha 的图层呢。
什么是 纯 alpha 的图层图片呢?通俗来讲,就是图片不要带颜色就可以了,当然UI设计师肯定知道,就是用 alpha 层去绘制图片吗,咱们也可以从 阿里巴巴的图片库下载,比如:

在这里插入图片描述

然后咱们设置一下
在这里插入图片描述
但是,发现默认还是灰色的,这里可以使用 setcolor 去设置:

 .setColor(getResources().getColor(R.color.colorPrimary)) 
  • 1

在这里插入图片描述
这里咱们就设置好了小图标了

1.1 设置点击事件

一般的通知栏都是可以点击的,但是我们点击了一下,发现并没有什么用。当然,我们都没设置点击事件。
notification 的点击事件,可以通过设置 setContentIntent 来实现。它需要传递一个 PendingIntent。从而实现点击之后的跳转意图。
PendingIntent 的用法也很简单,它可以通过 getActivity(),getBroadcast() 和 getService() 来获取不同的实例,一个简单获取 activity 的方法如下:

Intent intent = new Intent(this,SecondActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT); 
  • 1
  • 2

它的参数也比较简单,第一个为 context,第二个为 requestCode,一般用不到,intent 即你要跳转的意图。第四个参数有5种选择,分别如下:

  • FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的 PendingIntent 对象,那么就将先将已有的 PendingIntent 取消,然后重新生成一个 PendingIntent 对象。
  • FLAG_IMMUTABLE:创建的PendingIntent不可变,API23加入。
  • FLAG_NO_CREATE:如果当前系统中不存在相同的 PendingIntent 对象,系统将不会创建该 PendingIntent 对象而是直接返回 null 。
  • FLAG_ONE_SHOT:该 PendingIntent 只作用一次。
  • FLAG_UPDATE_CURRENT:如果系统中已存在该 PendingIntent 对象,那么系统将保留该 PendingIntent 对象,但是会使用新的 Intent 来更新之前 PendingIntent 中的 Intent 对象数据,例如更新 Intent 中的 Extras。

一般第四个传输,传递 0 或者FLAG_CANCEL_CURRENT 都可以。
所以,我们的通知代码改一下:

 mBuilder = new NotificationCompat.Builder(this)
                 .setContentTitle("这是标题")
                 .setContentText("我是内容,我是demo")
                 .setWhen(System.currentTimeMillis())
                 .setSmallIcon(R.mipmap.ic_launcher)
                 .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                 .setContentIntent(pi);
         //通过 builder.build() 拿到 notification
         mNotificationManager.notify(1, mBuilder.build()); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1.2 取消通知

点击之后,发现确实跳转了,但是通知栏还在。取消共有两种方式

  1. setAutoCancel(true) 在builder 那里,添加自动取消的功能
  2. mNotificationManager.cancel(1); 通过取消 id 取消,如果有 tag ,也可以使用 cancel(tag,id) 来取消

1.3 通知更新

更新通知,只需要重新 notify 相同的 id 即可,如果通知栏还在,则更新内容,如果不存在,则增加一个新的通知栏,如下,我们更新一下内容:

 mBuilder.setContentText("我更新了内容");
 mNotificationManager.notify(1,mBuilder.build()); 
  • 1
  • 2

在这里插入图片描述

二、通知栏效果

上面,咱们只是简单的实现了通知栏,但是一些好玩的效果,咱们并没有实现,这节,一起来看看通知栏的效果。

(请用真机测试)

2.1 声音

很多通知栏,都有声音的效果,同样,我们也可以设置。使用 setSound 即可实现,比如:

mBuilder = new NotificationCompat.Builder(this)
		  ...
         //这个看各自的手机的铃声的路径
          .setSound(Uri.fromFile(new File("system/media/audio/notifications/Argon.ogg")))
          .setAutoCancel(true); 
  • 1
  • 2
  • 3
  • 4
  • 5

除了自定义,还可以使用默认铃声:

.setDefaults(NotificationCompat.DEFAULT_SOUND) 
  • 1

2.2 震动

除了声音,还可以让手机震动,使用的是 setVibrate,它的参数为一个 long 的数组,以 ms 为单位,如果我们想让手机震动1s,延时一秒,再震动一次,当然,它需要向申请权限

<uses-permission android:name="android.permission.VIBRATE"/> 
  • 1
.setVibrate(new long[]{0,1000,1000,1000}) 
  • 1

同理,也可以使用默认震动效果:

.setDefaults(NotificationCompat.DEFAULT_VIBRATE) 
  • 1

2.3 LED灯

现在手机都LED灯,在手机息屏或者未接来电灯,还是还有必要的。同样,可以使用 setLights() 来实现效果。它又三个参数,第一个是设置灯的颜色,第二个是灯亮的时间,第三个则是灯暗的时间。如下:

.setLights(Color.RED,1000,1000) 
  • 1

同理,用默认的

.setDefaults(NotificationCompat.DEFAULT_LIGHTS) 
  • 1

ps:在国内百花齐放的环境中,上面那玩意基本无效,只能看各自的厂商的说明文档去适配了。

如果你觉得,上面的设置太麻烦,还有一个方法,直接全部设置成默认的:

.setDefaults(NotificationCompat.DEFAULT_ALL) 
  • 1

三、Notification 的高级玩法

在实际应用中,我们常常需要配合一下实际场所来灵活应用通知栏。比如长文字,打图片、回复信息、或者跳转等。下面一起来学习。

3.1 优先级

优先级在 7.1 及以下有用,8.0 则使用 channel 来设置。
通知栏是可以设置优先级的,它有5个常亮可以选

  • PRIORITY_DEFAULT 默认优先级
  • PRIORITY_MIN 优先级最低,某个特定场合才显示
  • PRIORITY_LOW 优先级较低,系统可能将这类通知缩小,或者改变它的显示位置,比如靠后的位置
  • PRIORITY_HIGH 表示较高程度,系统可能对它进行方法,或者改变位置,比如靠前的位置
  • PRIORITY_MAX 优先级最高,这类通知会让用户立刻看到

比如,我们设置了 PRIORITY_MAX ,直接回显示出通知栏的效果:
在这里插入图片描述

3.2 setStyle 展开式通知

很多时候,我们想显示一段比较长的文字,或者一个比较大的图片,使用默认的 setContentText 或者 setLargeIcon 是不行的,但是可以使用 setStyle ,setStyle 可以让通知栏变大来显示通知。

3.2.1 长文字

比如,显示一段长文字:

.setStyle(new NotificationCompat.BigTextStyle().bigText("我是内容,我是demo\n我不是测试\n 我是长文字啊")) 
  • 1

效果如下:
在这里插入图片描述

3.2.2 大图片

设置一张图片:

 .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.update_app_top_bg))
               .setStyle(new NotificationCompat.BigPictureStyle()
                       .bigPicture(BitmapFactory.decodeResource(getResources(),
                       R.mipmap.update_app_top_bg)).bigLargeIcon(null)
               ) 
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

3.3 添加按钮

一个通知最多可以提供三个操作按钮,然该用户可以快速响应,比如暂停,上一曲下一曲这些常用的按钮,这里,可以通过 addAction 去编写,并把 PendingIntent 关联进去,比如广播:

mBuilder = new NotificationCompat.Builder(this)
     ......
        .addAction(R.mipmap.enter,"上一曲",pi)
        .addAction(R.mipmap.enter,"开始",pi)
        .addAction(R.mipmap.enter,"下一曲",pi); 
  • 1
  • 2
  • 3
  • 4
  • 5

效果如下:
在这里插入图片描述

3.4 添加回复操作

google 在 Android 7.0 (API 24) 中引入允许用户直接回复的的组件,使用 RemoeInput 设置好key,并把它交给 action,即可实现。先看效果
在这里插入图片描述
首先,创建 RemoteInput.Builder() 的实例,并设置好 key 值,这个后面在 intent 会拿到。
然后,创建 PendingIntent,为了方便实验,添加一个广播
最后,创建 Action,把 remoteInput 和 pendingIntent 穿进去,代码如下:

 private NotificationCompat.Action getRemoveAction(){
     //添加一个回复组件,
     RemoteInput remoteInput = new RemoteInput.Builder(REPLY_KEY)
             .build();

     //添加一个 pendingIntent 的广播
     PendingIntent replyPi = PendingIntent.getBroadcast(this,2,
             new Intent("com.zhengsr.test"),PendingIntent.FLAG_UPDATE_CURRENT);

     //构建 action
     NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.enter,
             "回复",replyPi).addRemoteInput(remoteInput).build();

     return action;

 } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

然后直接添加 action 即可:

 mBuilder = new NotificationCompat.Builder(this)
   				....
                .addAction(getRemoveAction())
            ; 
  • 1
  • 2
  • 3
  • 4

3.4.1 拿到回复内容

如果想要拿到用户的输入内容,则可以调用 RemoteInput.getResultsFromIntent(intent) ,即可拿到 Bundle 并拿到数据,如:

 class  MyBroadcastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Bundle bundle = RemoteInput.getResultsFromIntent(intent);
            if (bundle != null) {
                String replay = bundle.getString(REPLY_KEY);
                Log.d(TAG, "zsr onReceive: "+replay);
            }
        }
    } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述
同样,也可以使用 NotificationCompat.MessagingStyle 去专门传递消息。具体参考官方资料。

3.5 显示进度条

通知栏还可以显示进度条,在 builder 中使用 setProgress。
在这里插入图片描述

setProgress(int max, int progress, boolean indeterminate) 
  • 1

参数都能看得明白。比如,当我们开始的进度条,可以设置为:

setProgress(100,0,false) 
  • 1

更新的话,直接改变 progress 即可,如果想要取消,则 setProgress(0,0,false)就可

3.6 显示紧急通知

在某些情况下,就算屏幕锁屏了,一些通知还是要显示的,比如电话,闹钟等。当然,通知栏也支持,根据设备的情况,会分两种情况

  • 设备锁定 : 如果设备锁定了,则显示全屏的 Acitivyt,直接覆盖全屏
  • 设备为锁定: 则还是以通知栏的形式出现

可以通过设置 setFullScreenIntent(PendingIntent intent ,boolean highPriority) 来设置,如:

 mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("紧急通知")
                .setContentText("这是一条紧急通知")
                .setWhen(System.currentTimeMillis())
                ..
                .setFullScreenIntent(pi,true) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中 pi 为你要跳转的 PendingIntent。除了默认的情况,还可以通过设置 setVisibility(int visibility) 来设置锁屏屏幕的范围,共有三种选择:

  • VISIBILITY_PUBLIC 显示通知的完整内容。
  • VISIBILITY_SECRET 不在锁定屏幕上显示该通知的任何部分。
  • VISIBILITY_PRIVATE 显示基本信息,例如通知图标和内容标题,但隐藏通知的完整内容。你如,显示"您有三条新短信",但是发件人和内容不可见。

四、自定义布局

一般情况下,系统的通知,并不能满足我们的需求,且为了保证每个版本的样式统一。都会采用自定义布局的形式。
需要注意的是。在创建自定义布局的时候,我们需要提供两个 layout,一个收起的视图,它的高度上限为 64dp。一个是展开之后,它的上限为 256dp

4.1 为内容区域创建自定义布局

一般的自定义布局中,我们可以借助通用模板去构建一个基本布局,即保留时间戳,通知图标等装饰,而自定义由标题和文本内容的区域。
这个时候,可以使用 NotificationCompat.DecoratedCustomViewStyle 设置到 style 中,一般步骤如下:

  1. 构建基本通知,使用NotificationCompat.Builder
  2. 调用 setStyle().想其传递 NotificationCompat.DecoratedCustomViewStyle 实例
  3. 将其自定义布局扩展为 RemoveteViews 实例
  4. 调用 setCustomContentView 设置收起的通知布局
  5. 调用 setCustomBigContentView 设置扩展的通知布局

如果为多媒体播放控件创建自定义通知。可以使用NotificationCompat.DecoratedMediaCustomViewStyle 类

例如:

RemoteViews cusRemoveView = new RemoteViews(getPackageName(),R.layout.cus_notify_small);
     RemoteViews cusRemoveExpandView = new RemoteViews(getPackageName(),R.layout.cus_notify_large);

     mBuilder = new NotificationCompat.Builder(this)
             .setWhen(System.currentTimeMillis())
             .setSmallIcon(R.mipmap.ic_launcher)
             .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
             .setCustomContentView(cusRemoveView)
             .setCustomBigContentView(cusRemoveExpandView); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其中,当我们在自定义布局时,通知的背景颜色可能因为版本而异,如果要跟随系统,在设置 TextView 控件时,可以使用 TextAppearance_Compat_Notification 样式,比如标题的TextAppearance_Compat_Notification_Title。 这样就能保证在不同版本中,textview 始终是正常显示的。比如 R.layout_cus_notify_small:

注意,目前layout只支持 LinearLayout、FrameLayout、RelativeLayout三种基本布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="64dp"
    android:orientation="vertical"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextAppearance.Compat.Notification.Title"
        android:text="我是标题"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextAppearance.Compat.Notification.Info"
        android:text="我是内容"/>


</LinearLayout> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

而,R.layout_cus_notify_large 中,给其中一个 TextView设置红色,不设置 style,看看效果:
在这里插入图片描述
在这里插入图片描述
避免在 RemoteViews 上设置背景颜色,可能会导致文办颜色无法读取的问题

4.2 创建完全的自定义通知背景

如果你不想用系统的时间戳,通知图标等。可以去掉 setStyle(),只添加 setCustomContentView 和 setCustomBigContentView 即可。
在这里插入图片描述
在这里插入图片描述

要支持低于 Android 4.1(API 级别 16)的 Android 版本,您还应调用 setContent(),向其传递同一 RemoteViews 对象。

如需获取更多使用通知的示例代码,请参阅 Android 通知示例