就像windows系统里最普通但是被设置了TOPMOST的EX_STYLE的窗口一样,具体来说就是不独占全屏,不独占焦点,可移动,可改变大小,总在最顶层的窗口。主要用来做网络流量的流量计,或者给后台运行的需要随时观察数据变化的程序一个大点的观察窗口之类的用途。google了很久,只找到了一些似是而非的方案,主要有下面2个说法:1,将 Activity 的 Theme 设置为 Theme.Dialog,Theme.Panel,Theme.InputMethod 之类,这样做的实际效果是,分别将窗口的 windowFrame,windowIsFloating,windowIsTranslucent,disabledAlpha 以各种方式组合得来,都无法达到要求的效果。2,使用 PopupWindow,但是 PopupWindow 必须有一个 View 作为 parent,这就避不开 Activity 全屏独占的问题,而且当其下的 Activity 切换的时候这个popupWindow也没了,所以也不行。
不知道有没有高手找到解决方法?
不知道有没有高手找到解决方法?
比如,想同时看到背后屏幕和拖动窗口的信息,这就是个很好的实现方法。如果能够把窗口部分拖出屏幕就更好了。notification还是不能满足同时看见的要求。我也来试试看怎么做到。
如2楼所说,只是需要找出这样一个机制,流量统计窗口实际上只是其中一种应用而已。这样的机制在windows下是天生的,但是在andriod上由于其ui体系的设计特性——考虑到小屏幕显示设备上不适宜出现跨进程的多窗口重叠——而没有官方的渠道做到这一点。目前我能做到让窗口显示在其他顶层之上,但是在交互上会出现应用程序焦点独占的问题。基本思路是使用 WindowManager.addView 来创建这种漂浮窗口,窗口的具有 TYPE_SYSTEM_ALERT 属性,保证了其始终位于顶层。由于 Activity 是全屏独占的,会屏蔽掉其下方的窗口与用户操作的交互,所以 WindowManager 不能依赖在 Activity 上,而只能在 Service 中调用。具体做法是:
1. 应用必须具有 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"></uses-permission> 的权限
2. 从一个 Activity 启动,在该 Activity 中 startService,然后在 Service 中调用 WindowManager.addView,被添加的 view 应该设置 FLAG_NOT_TOUCH_MODAL 标志
3. 为成为漂浮窗口的 view 设置 OnTouchListener,处理 OnTouch 事件的 ACTION_DOWN 和 ACTION_MOVE 使漂浮窗体可以被拖动
4. 在窗体关闭的过程中 finishService,或者在漂浮窗体计数器上减1之类,保证Service能够被正确结束但是这种实现有焦点独占的问题:当漂浮窗口存在于屏幕上时,焦点将始终处于悬浮窗口上。有一种折中的办法是,为 view 设置 FLAG_WATCH_OUTSIDE_TOUCH 标志,然后在 ACTION_OUTSIDE 中将 view 设置为 setFocusable(false)。但是这样的话,在放弃焦点之后就无法再对悬浮窗口进行操作了。现在有2个问题:
1. 如果不使 view 放弃焦点,那么如何使焦点正常转移到下方的 Activity 上?
2. 如果使 view 在 ACTION_OUTSIDE 中放弃焦点,那么如何使交互操作进入悬浮窗口所在区域的时候重新使悬浮窗口获取焦点?以上2个问题只要能解决一个就可以了。
第1个问题设计到ui体系的框架设计了,大概没什么后天的办法可以改动,除非修改ui体系的设计,估计难度很大。
第2个问题,如果有全局监听输入事件(主要是触摸事件的ACTION_DOWN)的发生坐标的方法,就可以解决这个问题,还请牛人支招。
2.如果有全局监听输入事件(主要是触摸事件的ACTION_DOWN)的发生坐标的方法
这个应该容易实现吧?
继续调查一下,应该有办法获得当前触摸点的坐标
MotionEvent可以获取当前的坐标
For efficiency, motion events with ACTION_MOVE may batch together multiple movement samples within a single object. The most current pointer coordinates are available using getX(int) and getY(int). Earlier coordinates within the batch are accessed using getHistoricalX(int, int) and getHistoricalY(int, int).
对于没有焦点的窗口是拿不到这个事件的,Touch事件只会像当前具有焦点的窗口广播。前面说的解决方案中,在 ACTION_OUTSIDE 里面已经将本窗口设置为没有焦点了,所以放弃焦点之后即使是点在悬浮窗口的区域也是拿不到事件的,这个事件会直接发送到悬浮窗口之下的那一层去。
(
new OnClickListener()
{
@Override
public void onClick(View v)
{
// This is the first way to customize Toast
// center and shift 50px to right, 100px down
tView.setGravity(Gravity.CENTER_VERTICAL, 50, -150);
tView.setText("This is a Custom Toast\nScreen is clicked\nGravity: Virtical Center, X 50, Y -150\nDuration: LONG");
tView.setDuration(Toast.LENGTH_LONG); tView.show();
}
}
);我点了下tView这个toast,他动了一下,表明点在toast上面其实主view时间监听的。你自己试试看onTouchAOA(傲卓网)
根本解决方案:扩展一个UI componet,更改framework层焦点处理manage和触摸事件分发机制,对此UI componte进行特殊处理。个人建议回避这个问题,选择下述方案:
更改你的APP layout,把你需要加的这个小窗口作为整个activity的一部分进行处理,比如设计成是activity的一个item,放在底部或者顶部,不然现有机制无法解决。这样做功能能实现,只是效果差一点。
布局文件里用FrameLayout布局
全屏的最底层 和 浮动的上层 分别放在两个Layout中
上层覆盖住底层的一部分
上层和没被盖住的底层可以同时获得焦点
2.当touch事件发生在悬浮窗口区域内部时,该touch事件能够被悬浮窗口捕捉到
请参考上面的源码
我也在思考它是怎么做出来的。不知道楼主实现了没?
Share ?