在狀態列上顯示會閃爍的圖示(類似qq訊息提示)
PS:看了9年的小說,自己開始動手寫了一本,請各位猿們動動手指,點選下,有起點賬號的可以收藏下!!《武意長存》
前兩週公司接了個執行在車機上的行車記錄儀小專案,在做完提交給對方公司測試後,他們提出了當程式在後臺錄影時,需要在狀態列上顯示個閃爍的圖示給使用者進行提示。
好吧,雖然對方給的需求文件上沒這個功能,但既然提了那就做吧。
要想完成這個功能,我首先想到的就是利用Notification,我們只需要迴圈的傳送圖示不同的Notification就行實現,是不是很簡單。當然最後我才發現這個方法在手機實現閃爍圖示提示沒問題,但在車機上卻不管用,這個後面再講。還是先來先講講使用Notification
介面很簡單就兩個按鈕,一個用來開啟閃爍提示,一個用來關閉。主要實現程式碼放置服務中,介面如下
按鈕點選執行程式碼:
@Override public void onClick(View v) { Intent service = new Intent(this, MyService.class); switch (v.getId()) { case R.id.btn_start: startService(service); break; case R.id.btn_stop: stopService(service); break; } } MyService.java public class MyService extends Service { private static final int MSG_ADD_ICON = 400; private static final int NOTIFICATION_ID_ICON = 666; private NotificationManager nm; private Notification notification; private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_ADD_ICON: boolean flag = (Boolean) msg.obj; addIconToStatusbar(flag); break; } }; }; @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { super.onCreate(); nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); addIconToStatusbar(true); } @Override public void onDestroy() { mHandler.removeMessages(MSG_ADD_ICON); nm.cancel(NOTIFICATION_ID_ICON); super.onDestroy(); } @SuppressLint("NewApi") private void addIconToStatusbar(boolean isShow) { if (notification == null) { notification = new Notification(); notification.icon = R.drawable.notification; notification.iconLevel = Integer.MAX_VALUE; // 將此通知放到通知欄的"Ongoing"即"正在執行"組中 notification.flags |= Notification.FLAG_ONGOING_EVENT; notification.flags |= Notification.FLAG_INSISTENT; notification.flags |= Notification.FLAG_HIGH_PRIORITY; // 表明在點選了通知欄中的"清除通知"後,此通知不清除, // 經常與FLAG_ONGOING_EVENT一起使用 notification.flags |= Notification.FLAG_NO_CLEAR; Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); notification.contentIntent = pendingIntent; notification.setLatestEventInfo(this, "DudooDVR", "正在錄影", pendingIntent); } if (isShow) { notification.icon = R.drawable.notification; } else { notification.icon = R.drawable.notification2; } nm.notify(NOTIFICATION_ID_ICON, notification); Message msg = Message.obtain(); msg.what = MSG_ADD_ICON; msg.obj = !isShow; mHandler.sendMessageDelayed(msg, 800); } }
程式碼其實很簡單,就是利用handler,迴圈傳送延遲訊息,每次只需要根據isShow標記替換圖示即可,這裡我準備的是一張紅色圓點小圖示和一張一樣大小的透明圖示。
效果如下:
如果只是在手機上使用,這樣就完成了,但悲催的是在車機上一執行,根本就沒效果。
原來車機上Notification並不會顯示在狀態列上,只有當你下拉狀態列,然後點選通知按鈕才能進入檢視通知。當然這有可能只是我們要執行的這款車機是這種情況,沒辦法,都是定製過的系統。(由於寫這篇文章是在宿舍,沒辦法截圖車機上的效果,大家自己想象,哈哈...)
好吧,本以為輕鬆搞定,沒想到程式碼白敲了。鬱悶歸鬱悶,功能還是要實現的,那該怎麼來實現了呢,我能想到的就是利用WindowManager
不過這裡得做個提醒,這個方法用在手機不好,會和其他通知重疊,只能用在我上面提到的狀態不顯示Notification的情況下。好吧,廢話不好多說,上程式碼吧
public class RedPoint {
private static final int FLASH_DELAY_TIME = 1000;
private static final int MSG_FLASH = 1;
public static final int REDPOINT_HEIGHT = 15;
public static final int REDPOINT_POSITION_X = 15;
public static final int REDPOINT_POSITION_Y = 7;
public static final int REDPOINT_WIDTH = 15;
private static boolean hasRedpoint = false;
private static RedPoint mRedPoint;
private static WindowManager redPointWm;
boolean isShouldFlash;
private Context mContext;
private WindowManager.LayoutParams redPointParams;
private View redpointFramelayout;
private Handler mHandler = new Handler() {
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
switch (msg.what) {
case MSG_FLASH: {
if (hasRedpoint) {
redpointFramelayout.setVisibility(isShouldFlash ? View.VISIBLE : View.INVISIBLE);
isShouldFlash = (!isShouldFlash);
mHandler.sendEmptyMessageDelayed(MSG_FLASH, FLASH_DELAY_TIME);
break;
}
}
}
}
};
public RedPoint(Context paramContext) {
this.mContext = paramContext;
init();
}
public static RedPoint getInstance(Context context) {
synchronized (RedPoint.class) {
if (mRedPoint == null) {
mRedPoint = new RedPoint(context);
}
}
return mRedPoint;
}
private void init() {
redPointWm = (WindowManager) this.mContext.getSystemService("window");
initRedPointWm();
}
private void initRedPointWm() {
this.redPointParams = new WindowManager.LayoutParams();
// 期望的點陣圖格式。預設為不透明。參考android.graphics.PixelFormat。
// 1 表示 RGBA_8888
this.redPointParams.format = 1;
this.redPointParams.width = 30;
this.redPointParams.height = 30;
this.redPointParams.x = 15;
this.redPointParams.y = 7;
// Gravity.AXIS_PULL_BEFORE | Gravity.AXIS_SPECIFIED | Gravity.TOP 這個值等於51
this.redPointParams.gravity = Gravity.AXIS_PULL_BEFORE | Gravity.AXIS_SPECIFIED | Gravity.TOP;
this.redPointParams.type = LayoutParams.TYPE_SYSTEM_OVERLAY; // 設定視窗的級別
// 312 相當於
// LayoutParams.FLAG_LAYOUT_IN_SCREEN | LayoutParams.FLAG_NOT_FOCUSABLE
// | LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL;
this.redPointParams.flags = 312;
this.redpointFramelayout = View.inflate(this.mContext, R.layout.redpoint, null);
}
private void startFlash(boolean isFlash) {
if (isFlash) {
isShouldFlash = true;
mHandler.sendEmptyMessage(MSG_FLASH);
return;
}
mHandler.removeMessages(MSG_FLASH);
}
public void addRedPointWm() {
if (!hasRedpoint) {
try {
redPointWm.addView(redpointFramelayout, redPointParams);
hasRedpoint = true;
startFlash(true);
return;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void removeRedPointWm() {
if (hasRedpoint) {
startFlash(false);
try {
redPointWm.removeView(redpointFramelayout);
} catch (Exception e) {
e.printStackTrace();
}
hasRedpoint = false;
}
mHandler.removeCallbacksAndMessages(MSG_FLASH);
}
}
RedPoint 類用於閃爍圖示的管理,其實還是利用handler傳送延遲訊息,迴圈的顯示和隱藏新增到螢幕上的view。
我們只需要在服務開啟的時候呼叫addRedPointWm方法,把view新增到螢幕中,然後在關閉服務時呼叫removeRedPointWm方法就可以了。至於新增時設定的一些引數註釋也寫得挺清楚了,不清楚的請自行百度或者谷歌
對了,由於我們設定成的是系統級別的window,所以別忘了新增上許可權
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
由於在宿舍沒車機,就用大概看下手機實現後的效果吧