1. 程式人生 > >Android 在所有應用的上層彈出可拖動的View

Android 在所有應用的上層彈出可拖動的View

                 最近facebook Messenger添加了一個新的特性chatHead,這個圖示可以脫離所有的介面,顯示在android手機的所有應用的最上面。研究了下。記錄如下。

             首先想到的是用一個透明的Activity來搞這個事情,想來facebook不會這麼愚蠢,試了下果然猜對了:

adb shell dumpsys activity,沒有發現相關activity。
    其實facebook用的是service。adb shell dumpsys activity services下發現果然找到了其service。
    解釋下實現原理。
    很簡單,就是將一個View新增到Window裡。我們知道,一個Activity有一個Window例項,Dialog也有他們自己的專用例項,Service也可以有一個Window。比如說InputMethodService可以用一個Window去接收Touch事件然後在任意一個Window的上面繪製一個鍵盤。DreamService用來建立屏保。
    為了顯示一個新的Window,需要加入如下許可權:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
public class ChatHeadService extends Service {
	private WindowManager windowManager;
	private ImageView chatHead;

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
		chatHead = new ImageView(this);
		chatHead.setImageResource(R.drawable.ic_launcher);

		WindowManager.LayoutParams params = new WindowManager.LayoutParams(
				WindowManager.LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.TYPE_PHONE,
				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
				PixelFormat.TRANSLUCENT);

		params.gravity = Gravity.TOP | Gravity.LEFT;
		params.x = 0;
		params.y = 100;

		windowManager.addView(chatHead, params);

		setChatHeadTouchListener(params);
	}

	private void setChatHeadTouchListener(final WindowManager.LayoutParams params) {
		chatHead.setOnTouchListener(new View.OnTouchListener() {
			private int initialX;
			private int initialY;
			private float initialTouchX;
			private float initialTouchY;

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					initialX = params.x;
					initialY = params.y;
					initialTouchX = event.getRawX();
					initialTouchY = event.getRawY();
					return true;
				case MotionEvent.ACTION_UP:
					return true;
				case MotionEvent.ACTION_MOVE:
					params.x = initialX
							+ (int) (event.getRawX() - initialTouchX);
					params.y = initialY
							+ (int) (event.getRawY() - initialTouchY);
					windowManager.updateViewLayout(chatHead, params);
					return true;
				}
				return false;
			}
		});
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if (chatHead != null) {
			windowManager.removeView(chatHead);
		}
	}
}
方法setChatHeadTouchListener可以使這個view可以在Window上隨意拖動。
      別忘了在想顯示Window的時候開啟服務。
startService(new Intent(this, ChatHeadService.class));
這樣你就能看到一個可愛的Window顯示在所有的應用程式上面了。
程式碼地址:http://download.csdn.net/detail/liuhanhan512/7208705
有問題交流。