Android实现自定义通知栏

1,414 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

1、什么是通知栏

通知栏是在应用界面外部显示消息的组件,用于向用户推送消息,用户可以通过点击通知栏直接进入应用的某个页面。

Android系统内置了通知的系统模板,通过模板可以轻松实现通知栏,且不需要对各个品牌的手机进行适配。但同时也开放了自定义通知栏,可以通过RemoteViews实现。

2、自定义通知栏的实现以及注意事项(布局、主题)

自定义通知栏主要通过NotificationCompat.Builder.setCustomContentView(RemoteViews)进行实现:

public static void showEnterAppNotification(Context context) {
    //获取NotificationManager
    NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    //创建RemoteViews,第二个参数填入自定义的布局文件,注意RemoteViews不支持ConstraintLayout
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.view_notification);
    //将remoteViews设置进builder
    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setOnlyAlertOnce(true)
            .setWhen(System.currentTimeMillis())
            .setShowWhen(true)
            .setSmallIcon(R.mipmap.ic_small_logo)
            .setAutoCancel(true)
            .setOngoing(true)
            .setCustomContentView(remoteViews);
    //设置优先级
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        builder.setPriority(NotificationManager.IMPORTANCE_HIGH);
    } else {
        builder.setPriority(Notification.PRIORITY_HIGH);
    }
    //设置点击通知栏要跳转的Activity
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra(Constants.EXTRA.NOTIFICATION_FROM, Constants.NotificationType.FROM_NOTIFICATION);
    intent.putExtra(Constants.EXTRA.NOTIFICATION_TYPE, NOTIFICATION_CODE);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, NOTIFICATION_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    builder.setContentIntent(pendingIntent);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE);
    }
    //Android8以上需要设置通知渠道
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel mNotificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
        mNotificationChannel.setDescription(CHANNEL_DESCRIPTION);
        mNotificationChannel.setSound(null, null);
        manager.createNotificationChannel(mNotificationChannel);
        builder.setChannelId(CHANNEL_ID);
    }
    //推送通知
    manager.notify(NOTIFICATION_CODE, builder.build());
}

注意:

  • Android8以上需要为通知创建渠道,通知才能正常推送。为渠道设置优先级和描述,用户可以在设置中根据需要对该渠道的通知进行屏蔽。
  • RemoteViews支持的布局和组件有限,如下:

image.png

  • 如果自定义布局没有设置背景色,会使用系统默认的背景色。需要对布局中所用到的颜色设置日间模式和夜间模式,以适配手机的两种模式。
3、适配到小米手机,

在进行真机测试时,发现小米8手机的自定义通知栏高度被压缩了。通知栏的布局设置了padding,在其他品牌的手机可以正常显示。如果把padding去掉,在小米手机上可以正常显示,高度不会被压缩,且自带padding。但其他品牌的手机通知栏没有自适应padding,非常不美观。从布局上无法解决的问题,可以从代码上进行解决。通过Build.BRAND获取品牌名,直接通过remoteView.setPadding(id,start,top,right,bottom)设置内边距,id直接填写自定义布局最外层组件的id,其他四个参数按照左上右下顺时针的方向填入边距,如下。

//小米:Xiaomi,谷歌:google,OPPO:OPPO,三星:samsung
if (!"Xiaomi".equals(Build.BRAND)) {
    int padding = dp2px(context, 16);
    remoteViews.setViewPadding(R.id.container, padding, padding, padding, padding);
}
        
public int dp2px(Context context, float dp) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dp * scale + 0.5f);
}