Android 在所有应用的上层弹出可拖动的View

本文解析了Facebook Messenger中ChatHead特性的实现原理。通过在Android设备上创建一个可浮动且可拖动的视图,使得ChatHead能够在所有应用之上显示。文章详细介绍了使用Service而非Activity来实现这一功能的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                 最近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.youkuaiyun.com/detail/liuhanhan512/7208705
有问题交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值