1. 程式人生 > >在狀態列上顯示會閃爍的圖示(類似qq訊息提示)

在狀態列上顯示會閃爍的圖示(類似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

往螢幕上新增一個全域性的view,當然有可能還有其他更好的實現方法。

不過這裡得做個提醒,這個方法用在手機不好,會和其他通知重疊,只能用在我上面提到的狀態不顯示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"/>

由於在宿舍沒車機,就用大概看下手機實現後的效果吧