起因
很久之前接到一個需求斑匪,需要在通知欄常駐一個notification,title和subtitle都比較短锋勺,在末尾加一個類似數(shù)據(jù)狀態(tài)的提示秤标。常駐notification很簡單,通過service發(fā)送一個前臺服務(wù)就可以了宙刘,自定義RemoteViews也很簡單苍姜,寫好對應(yīng)的layout就好了,大體樣式可以做的跟系統(tǒng)的notification差不多悬包。
但是發(fā)現(xiàn)做完之后衙猪,在各種手機上的performance相差很多,特別是小米的布近,簡直奇丑無比垫释,除非把整個色塊全都上色,類似360那種撑瞧。出于強迫癥棵譬,十分想把這個notification做的跟系統(tǒng)一個樣式,這樣可以適配各大手機预伺。于是開始對系統(tǒng)源碼以及hierarchyViewer進行分析订咸。
分析
- 通過hierarchyViewer,理清楚SystemUI中notification item的視圖結(jié)構(gòu)酬诀;查找源碼了解到對應(yīng)layout的布局情況脏嚷。
- 如果可以保留notification原本的layout,然后整體添加到新的layout中瞒御,即可保留系統(tǒng)樣式父叙,
- 然后往新的layout中添加顯示數(shù)據(jù)狀態(tài)的view。
hierarchyViewer
system_ui_notification_item_desc.jpg
找到了notification布局中Notification item layout中肴裙,RemoteViews的contentView的id為“status_bar_latest_event_content”
代碼實現(xiàn)
public static void senNotification(Context context) {
...
//通過反射找到對應(yīng)parent的id
int id = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "android");
Notification notification;
//如果找到了id則自定義notification趾唱,否則照常
if (id != 0) {
//new一個notification,通過setXXX設(shè)置好action蜻懦,然后build出來
notification = new NotificationCompat.Builder(context).setContentTitle("這是一個自定義的notifications")
.setContentText("能保留系統(tǒng)Notification中title和subtitle的style").setContentIntent(pendingIntent)
.setAutoCancel(true).setSmallIcon(R.mipmap.ic_launcher).setShowWhen(false).build();
//把系統(tǒng)樣式的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);
//把系統(tǒng)樣式的RemoteView添加到自定義Parent中
customParentView.addView(R.id.custom_notification_item_parent, contentView);
//把現(xiàn)實數(shù)據(jù)狀態(tài)的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 {
//正常發(fā)送notification
...
}
//常駐notification需要在service中通過發(fā)送前臺服務(wù)實現(xiàn)阻肩,此處不贅述带欢,就簡單發(fā)送一個通知
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" />
這樣运授,一個風格適配系統(tǒng)的自定義notification就完成了,不過目前有一個弊端還無法解決乔煞,就是title和subtitle太長吁朦,就會被自定義的child遮擋,不過就之前的需求而言渡贾,目前的實現(xiàn)足夠滿足了逗宜。