美文网首页
自定义系统样式Notification

自定义系统样式Notification

作者: Android_Yann | 来源:发表于2017-02-21 22:25 被阅读0次

    起因

    很久之前接到一个需求,需要在通知栏常驻一个notification,title和subtitle都比较短,在末尾加一个类似数据状态的提示。常驻notification很简单,通过service发送一个前台服务就可以了,自定义RemoteViews也很简单,写好对应的layout就好了,大体样式可以做的跟系统的notification差不多。

    但是发现做完之后,在各种手机上的performance相差很多,特别是小米的,简直奇丑无比,除非把整个色块全都上色,类似360那种。出于强迫症,十分想把这个notification做的跟系统一个样式,这样可以适配各大手机。于是开始对系统源码以及hierarchyViewer进行分析。

    分析

    1. 通过hierarchyViewer,理清楚SystemUI中notification item的视图结构;查找源码了解到对应layout的布局情况。
    2. 如果可以保留notification原本的layout,然后整体添加到新的layout中,即可保留系统样式,
    3. 然后往新的layout中添加显示数据状态的view。

    hierarchyViewer

    system_ui_notification_item_desc.jpg

    找到了notification布局中Notification item layout中,RemoteViews的contentView的id为“status_bar_latest_event_content”

    代码实现

    public static void senNotification(Context context) {
        ...
            //通过反射找到对应parent的id
            int id = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "android");
            Notification notification;
            //如果找到了id则自定义notification,否则照常
            if (id != 0) {
                //new一个notification,通过setXXX设置好action,然后build出来
                notification = new NotificationCompat.Builder(context).setContentTitle("这是一个自定义的notifications")
                        .setContentText("能保留系统Notification中title和subtitle的style").setContentIntent(pendingIntent)
                        .setAutoCancel(true).setSmallIcon(R.mipmap.ic_launcher).setShowWhen(false).build();
                //把系统样式的RemoteViews 克隆一份
                RemoteViews contentView = notification.contentView.clone();
                //接着把parent的child全部清除,等待添加自定义的RemoteViews
                notification.contentView.removeAllViews(id);
                //自定义的parent,将被添加到notification.contentView
                RemoteViews customParentView = new RemoteViews(context.getPackageName(),
                        R.layout.layout_custom_notification);
                //把系统样式的RemoteView添加到自定义Parent中
                customParentView.addView(R.id.custom_notification_item_parent, contentView);
                //把现实数据状态的view添加到自定义Parent中
                RemoteViews customChildView = new RemoteViews(context.getPackageName(),
                        R.layout.layout_custom_notification_child);
                customChildView.setTextViewText(R.id.child, "Child");
                customParentView.addView(R.id.custom_notification_item_parent, customChildView);
                //把自定义Parent添加到contentView中
                notification.contentView.addView(id, customParentView);
            } else {
                //正常发送notification
                ...
            }
            //常驻notification需要在service中通过发送前台服务实现,此处不赘述,就简单发送一个通知
            notificationManager.notify(1, notification);
        }
    

    custom_notification_item_parent.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/custom_notification_item_parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_vertical">
    
    </RelativeLayout>
    

    layout_custom_notification_child.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/child"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_alignParentRight="true"
        android:layout_marginRight="8dp"
        android:gravity="center"
        android:background="@color/theme_white"
        android:textColor="@color/theme_black"
        android:textSize="14sp" />
    

    这样,一个风格适配系统的自定义notification就完成了,不过目前有一个弊端还无法解决,就是title和subtitle太长,就会被自定义的child遮挡,不过就之前的需求而言,目前的实现足够满足了。

    代码地址

    相关文章

      网友评论

          本文标题:自定义系统样式Notification

          本文链接:https://www.haomeiwen.com/subject/xmqpwttx.html