Android好奇宝宝_05_PopupWindow与悬浮窗

这一篇讲讲PopupWindow与悬浮窗之间那些不得不说的故事。

之所以把PopupWindow与悬浮窗这两个放到一起讲,是因为这两个的实现原理基本是一致的,只是有点不同而已。

原理:

使用系统服务(WindowManagerService)将要显示的View添加进Window中。


WindowManagerService和ActivityManagerService是Android系统中两个最重要的服务,其中一个管理窗口显示,一个管理四大组件。


ActivityManagerService这里呢先不讲,以后再说。


简单讲下WindowManagerService,想深入了解的建议看下老罗大大的博客,新手慎入:传送门


以一个最简单的HelloWorld来说明:

当Activity被启动时,Activity会被分配一个Window,一个window代表一个充满屏幕的窗口。然后当我们调用setContentView时,我们要显示的View(后面用contentView表示)就会被添加进该Activity的window中。window接收到contentView后会根据设置在其外部包裹一些其它view(比如titlebar),然后请求WindowManagerService,WindowManagerService则向底层一层一层发送请求直到硬件将其显示出来。


上面的说明简化了很多过程,因为不是我想讲的重点,这一篇只是想简单讲下怎么用WindowManagerService,而不是它的实现原理(原理我也讲不来。。)。


一般我们添加View的方式是将子view添加到一个已经存在于window上的父view中。但其实利用WindowManagerService我们是可以直接将view添加的window中的,就像系统帮我们自动将setContentView的contentView添加到window一样。


两种方式的主要区别在于子view添加进父view,那么子view和父view就位于同一个window,但用WindowManagerService添加view,我们可以指定不同window(如果你有足够权限的话),我这里说的不同window是指他们的等级不同。PopupWindow依附于Activity,属于应用级。而悬浮窗就是属于系统级,所以它才可以保持在前端显示(其它系统级的window还有来电提醒,ANR、FC等系统警告等)。


再说说WindowManagerService和WindowManager的区别:

WindowManagerService是系统服务,当并不完全对开发者开放,而是使用WindowManager做为代理,提供部分功能和包装后的功能,可以说WindowManager是阉割版的WindowManagerService,那些会危害系统安全的功能被屏蔽了。Android系统中的系统服务基本都是这种方式。


说完原理来看看代码证实一下,先看下系统实现的PopupWindow,在根据原理来实现一个悬浮窗。


PopupWindow:


其实PopupWindow里面只有两句核心的代码,其它的都是一些位置和大小的计算。

(1)在构造方法中,通过传入的context或则view获得WindowManager:

        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

或者:

            mContext = contentView.getContext();
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);


(2)通过 WindowManager将PopupWindow添加进window:

mWindowManager.addView(mPopupView, p);


是不是炒鸡简单?


那么我们来开始实现悬浮窗:


(1)先获取WindowManager:

mWindowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);

注意这里要使用Application的context来获取WindowManager,如果使用activity.getSystemService(Context.WINDOW_SERVICE)来获取的话,得到的WindowManager的生命周期是小于等于Activity的,而使用上面这种方式得到的WindowManager是跟整个应用一样的,这样除非你的整个应用进程都被终结了,不然你的悬浮窗就可以一直显示。


(2)设置参数WindowManager.LayoutParams:

大小位置等可以根据需求来设置,但是要记住设置显示的级别:

wmParams.type = LayoutParams.TYPE_PHONE;


(3)将要显示的view添加进window:

mWindowManager.addView(floatView, wmParams);

当然你也可以对floatView和其子view进行点击、触摸等事件的监听,然后可以通过 WindowManager的另一个方法来刷新floatView

mWindowManager.updateViewLayout(floatView, wmParams);


举个栗子:

你可以监听触摸事件,得到触摸位置并设置进wmParams里,再调用updateViewLayout方法来实现悬浮窗随手指移动的效果。


一点补充:网上的悬浮窗demo很多都是在Service中生成的,其实在Activity生成是一样的。但Service的有个好处是可以让应用进程不那么容易被杀死。


楼主写的一个demo效果图:


这里的吃豆人是我再另一篇博文写得demo摘出来的,没啥好说的,有兴趣的可以去支持下:

一个有吃豆人删除动画的ListView


本篇Demo下载


终于摆脱每一篇都是讲AbsListView的厄运了。


求赞求评论

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值