如何創(chuàng)建通知
隨著Android系統(tǒng)不斷升級耳幢,Notification的創(chuàng)建方式也隨之變化岳守,主要變化如下:
Android 3.0之前
Android 3.0 (API level 11)之前铲掐,使用new Notification()方式創(chuàng)建通知:
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, new Intent(this, ResultActivity.class), 0);
Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(this, title, content, contentIntent);
mNotifyMgr.notify(NOTIFICATIONS_ID, notification);
Android 3.0 (API level 11)及更高版本
Android 3.0開始棄用new Notification()方式位隶,改用Notification.Builder()來創(chuàng)建通知:
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, new Intent(this, ResultActivity.class), 0);
Notification notification = new Notification.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setContentIntent(contentIntent)
.build();// getNotification()
mNotifyMgr.notify(NOTIFICATIONS_ID, notification);
這里需要注意:
"build()" 是Androdi 4.1(API level 16)加入的怨规,用以替代
"getNotification()"絮吵。API level 16開始棄用"getNotification()"
兼容Android 3.0之前的版本
為了兼容API level 11之前的版本弧烤,v4 Support Library中提供了
NotificationCompat.Builder()這個(gè)替代方法。它與Notification.Builder()類似蹬敲,二者沒有太大區(qū)別暇昂。
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, new Intent(this, ResultActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setContentIntent(contentIntent);
mNotifyMgr.notify(NOTIFICATIONS_ID, mBuilder.build());
范例:
/**
* 普通樣式
*
* @param context
*/
private void simpleNotify(Context context) {
initNotificationManager(context);
//為了版本兼容 選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
//Ticker是狀態(tài)欄顯示的提示
builder.setTicker("簡單Notification");
//第一行內(nèi)容 通常作為通知欄標(biāo)題
builder.setContentTitle("標(biāo)題");
//第二行內(nèi)容 通常是通知正文
builder.setContentText("通知內(nèi)容");
//第三行內(nèi)容 通常是內(nèi)容摘要什么的 在低版本機(jī)器上不一定顯示
builder.setSubText("這里顯示的是通知第三行內(nèi)容!");
//ContentInfo 在通知的右側(cè) 時(shí)間的下面 用來展示一些其他信息
//builder.setContentInfo("3");
//number設(shè)計(jì)用來顯示同種通知的數(shù)量和ContentInfo的位置一樣伴嗡,如果設(shè)置了ContentInfo則number會(huì)被隱藏
builder.setNumber(2);
//可以點(diǎn)擊通知欄的刪除按鈕刪除
builder.setAutoCancel(true);
//系統(tǒng)狀態(tài)欄顯示的小圖標(biāo)
builder.setSmallIcon(R.drawable.notify_5);
//下拉顯示的大圖標(biāo)
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
Intent intent = new Intent(context, PendingActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
//點(diǎn)擊跳轉(zhuǎn)的intent
builder.setContentIntent(pIntent);
//通知默認(rèn)的聲音 震動(dòng) 呼吸燈
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
Notification notification = builder.build();
notificationManager.notify(TYPE_Normal, notification);
}
/**
* 多文本樣式
* @param context
*/
private void bigTextStyle(Context context) {
initNotificationManager(context);
//為了版本兼容 選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("BigTextStyle");
builder.setContentText("BigTextStyle演示示例");
builder.setSmallIcon(R.drawable.notify_5);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
android.support.v4.app.NotificationCompat.BigTextStyle style = new android.support.v4.app.NotificationCompat.BigTextStyle();
style.bigText("這里是點(diǎn)擊通知后要顯示的正文急波,可以換行可以顯示很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長");
style.setBigContentTitle("點(diǎn)擊后的標(biāo)題");
style.setSummaryText("末尾只一行的文字內(nèi)容");
builder.setStyle(style);
builder.setAutoCancel(true);
Intent intent = new Intent(context, PendingActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
builder.setContentIntent(pIntent);
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
Notification notification = builder.build();
notificationManager.notify(TYPE_BigText, notification);
}
/**
* 最多顯示五行 再多會(huì)有截?cái)? */
public void inBoxStyle(Context context) {
initNotificationManager(context);
//為了版本兼容 選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("InboxStyle");
builder.setContentText("InboxStyle演示示例");
builder.setSmallIcon(R.drawable.notify_5);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
android.support.v4.app.NotificationCompat.InboxStyle style = new android.support.v4.app.NotificationCompat.InboxStyle();
style.setBigContentTitle("BigContentTitle")
.addLine("第一行,第一行瘪校,第一行澄暮,第一行,第一行阱扬,第一行泣懊,第一行")
.addLine("第二行")
.addLine("第三行")
.addLine("第四行")
.addLine("第五行")
.setSummaryText("SummaryText");
builder.setStyle(style);
builder.setAutoCancel(true);
Intent intent = new Intent(context, PendingActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
builder.setContentIntent(pIntent);
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
Notification notification = builder.build();
notificationManager.notify(TYPE_Inbox, notification);
}
/**
* 大圖樣式
* @param context
*/
public void bigPictureStyle(Context context) {
initNotificationManager(context);
//為了版本兼容 選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("BigPictureStyle");
builder.setContentText("BigPicture演示示例");
builder.setSmallIcon(R.drawable.notify_5);
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
android.support.v4.app.NotificationCompat.BigPictureStyle style = new android.support.v4.app.NotificationCompat.BigPictureStyle();
style.setBigContentTitle("BigContentTitle");
style.setSummaryText("SummaryText");
style.bigPicture(BitmapFactory.decodeResource(context.getResources(), R.drawable.small));
builder.setStyle(style);
builder.setAutoCancel(true);
Intent intent = new Intent(context, PendingActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
builder.setContentIntent(pIntent);
Notification notification = builder.build();
notificationManager.notify(TYPE_BigPicture, notification);
}
/**
* 橫幅通知
*
* @param context
*/
private void hangup(Context context) {
initNotificationManager(context);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Toast.makeText(context, "此類通知在Android 5.0以上版本才會(huì)有橫幅有效!", Toast.LENGTH_SHORT).show();
}
//為了版本兼容 選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("橫幅通知");
builder.setContentText("請?jiān)谠O(shè)置通知管理中開啟消息橫幅提醒權(quán)限");
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
builder.setSmallIcon(R.drawable.notify_5);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
Intent intent = new Intent(context, PendingActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
builder.setContentIntent(pIntent);
builder.setFullScreenIntent(pIntent, true);
builder.setAutoCancel(true);
Notification notification = builder.build();
notificationManager.notify(TYPE_Hangup, notification);
}
自定義通知適配
默認(rèn)通知不存在樣式適配的問題麻惶,因?yàn)槟J(rèn)通知的布局馍刮、顏色、背景什么的都是系統(tǒng)的窃蹋,系統(tǒng)總會(huì)正確的顯示默認(rèn)通知渠退。但自定義通知就不一樣了,自定義通知的布局完全由我們自己掌控脐彩,我們可以為元素設(shè)置任何背景碎乃、顏色。那么惠奸,問題來了梅誓。Android通知欄的背景各種各樣,不同的ROM有不同的背景佛南,白色梗掰、黑色、透明等嗅回。不同的Android版本通知欄背景也不一樣及穗,一旦我們?yōu)樽远x通知上的元素設(shè)置了特定背景或顏色,就肯定會(huì)帶來兼容性問題
適配的方式大概有兩種:
一種簡單粗暴:為自定義通知設(shè)置固定的背景(上圖中的360衛(wèi)士就這么干的)绵载,比如黑色埂陆。那么內(nèi)容自然就是白色或近似白色苛白。這樣,在所有的手機(jī)上都能正常顯示焚虱,不會(huì)出現(xiàn)在黑色背景通知欄上顯示良好购裙,到了白色背景通知欄上就幾乎啥也看不見。
另一種方案就稍微合理一些:通過讀取系統(tǒng)的通知欄樣式文件鹃栽,獲取到title和content的顏色躏率,進(jìn)而將這個(gè)顏色設(shè)置到自定義通知上。讀取通知欄樣式文件本身有兼容性問題民鼓,不同Android版本的樣式文件有變薇芝,種方式也不是在所有手機(jī)上生效,實(shí)際測試發(fā)現(xiàn)丰嘉,還是有小部分機(jī)型沒法讀取或是讀取到的是錯(cuò)誤的夯到。拿到title和content的顏色后,還可以通過算法(后面細(xì)說)判斷這個(gè)顏色是近似白色還是近似黑色供嚎,進(jìn)而能判斷出通知欄的背景是近似黑色還是近似白色黄娘,這樣就能根據(jù)不同的通知欄背景加載不同的自定義通知布局峭状。進(jìn)而做到良好的適配克滴。
/**
* 讀取系統(tǒng)通知欄顏色工具類
* Created by liuboyu on 16/12/21.
*/
public class SystemColorUtils {
private static final String DUMMY_TITLE = "DUMMY_TITLE";
private static final double COLOR_THRESHOLD = 180.0;
private static int titleColor;
/**
* 獲取通知欄顏色
*
* @param context
* @return
*/
public static int getNotificationColor(Context context) {
// if (context instanceof AppCompatActivity) {
// return getNotificationColorCompat(context);
// } else {
return getNotificationColorInternal(context);
// }
}
/**
* 當(dāng)前狀態(tài)了是否為暗色
*
* @param context
* @return
*/
public static boolean isDarkNotificationBar(Context context) {
return !isColorSimilar(Color.BLACK, getNotificationColor(context));
}
/**
* notificationRoot了,不如就遍歷它优床,先找到其中的所有TextView
* 取字體最大的TextView作為title(這是合理的劝赔,
* 因?yàn)槟J(rèn)通知中最多也就4個(gè)TextView,分別是title胆敞、
* content着帽、info、when移层,title肯定是字體最大仍翰,最顯眼的)
*
* @param context
* @return
*/
public static int getNotificationColorCompat(Context context) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Notification notification = builder.build();
int layoutId = notification.contentView.getLayoutId();
ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
final TextView title = (TextView) notificationRoot.findViewById(android.R.id.title);
//ROM廠商會(huì)把id改掉,導(dǎo)致找到的title為空观话。
if (null == title) {
final List<TextView> textViews = new ArrayList<>();
iteratorView(notificationRoot, new Filter() {
@Override
public void filter(View view) {
if (view instanceof TextView) {
textViews.add((TextView) view);
}
}
});
float minTextSize = Integer.MIN_VALUE;
int index = 0;
for (int i = 0; i < textViews.size(); i++) {
float currentSize = textViews.get(i).getTextSize();
if (currentSize > minTextSize) {
minTextSize = currentSize;
index = i;
}
}
return textViews.get(index).getCurrentTextColor();
} else {
return title.getCurrentTextColor();
}
}
/**
* 5.0以下的機(jī)器
*
* @param context
* @return
*/
public static int getNotificationColorInternal(Context context) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Notification notification = builder.build();
int layoutId = notification.contentView.getLayoutId();
ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
final TextView title = (TextView) notificationRoot.findViewById(android.R.id.title);
if (null == title) {
iteratorView(notificationRoot, new Filter() {
@Override
public void filter(View view) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
if (DUMMY_TITLE.equals(textView.getText().toString())) {
titleColor = textView.getCurrentTextColor();
}
}
}
});
return titleColor;
} else {
Log.e("ddddd3ddd",""+title.getCurrentTextColor());
return title.getCurrentTextColor();
}
}
/**
* 遍歷 notificationRoot了
*
* @param view
* @param filter
*/
private static void iteratorView(View view, Filter filter) {
if (view == null || filter == null) {
return;
}
filter.filter(view);
if (view instanceof ViewGroup) {
ViewGroup container = (ViewGroup) view;
for (int i = 0, j = container.getChildCount(); i < j; i++) {
View childAt = container.getChildAt(i);
iteratorView(childAt, filter);
}
}
}
private interface Filter {
void filter(View view);
}
/**
* 使用方差來計(jì)算這個(gè)顏色是否近似黑色
*
* @param baseColor
* @param color
* @return
*/
public static boolean isColorSimilar(int baseColor, int color) {
int simpleBaseColor = baseColor | 0xff000000;
int simpleColor = color | 0xff000000;
int baseRed = Color.red(simpleBaseColor) - Color.red(simpleColor);
int baseGreen = Color.green(simpleBaseColor) - Color.green(simpleColor);
int baseBlue = Color.blue(simpleBaseColor) - Color.blue(simpleColor);
double value = Math.sqrt(baseRed * baseRed + baseGreen * baseGreen + baseBlue * baseBlue);
if (value < COLOR_THRESHOLD) {
return true;
}
return false;
}
}
使用范例:
if (SystemColorUtils.isDarkNotificationBar(context)) {
view.setTextColor(R.id.tv_title, context.getResources().getColor(R.color.white));
view.setTextColor(R.id.tv_des, context.getResources().getColor(R.color.white));
} else {
view.setTextColor(R.id.tv_title, context.getResources().getColor(R.color.black));
view.setTextColor(R.id.tv_des, context.getResources().getColor(R.color.black));
}
需要注意的是:
如果當(dāng)前工程已經(jīng)繼承 com.android.support:appcompat 可正常使用
如果當(dāng)前工程沒有繼承 com.android.support:appcompat 予借,AppBaseTheme 要繼承 @android:style/Theme.DeviceDefault.Light.DarkActionBar,本人暫時(shí)也沒有搞懂這是為什么频蛔,如果哪位大神知道灵迫,請給我留言,謝謝
<style name="AppBaseTheme" parent="@android:style/Theme.DeviceDefault.Light.DarkActionBar"></style>