当前位置:首页>编程日记>正文

Floating Window 详解

一,原理

1,全局悬浮

floating view可以悬浮在应用的各个页面。floating view是放在一个单独的window中。 对于每个app而言,它所在的window在floating view所在的window之下,这样,就可以悬浮在其至上。window可以设置相应的层级。比如,通知栏,就是在一个级别很高的window中。如果想要清晰的看清楚相应的结构,可以通过hierarchyviewer的工具,看view的层级关系。


2,全局移动

通过1,全局移动的关键其实是更改window的位置。关键是坐标的计算。一个坐标是绝对坐标,一个相对坐标。参看示意图,理解以下的计算公式即可。

Floating Window 详解 配图01

private void updateViewPosition() {mWindowLayoutParams.x = (int) (mRawX - mTouchStartX);mWindowLayoutParams.y = (int) (mRawY - mTouchStartY);mWindowManager.updateViewLayout(this, mWindowLayoutParams);}


3,运行状态监控。

floating view所在的显示层级高于app,所以如何控制其显示或者消失,比如类似360手机助手的显示机制。我们关注最多的有四种状态:

3-1 home(通过所有的launcher相应的包名筛选)

2-2 应用内 (通过指定包名)

3-3 应用某个特定页面 (通过指定的完整类名)

3-3 其他状态(其他应用,etc)(排除之后,剩下的情况)

所以,其实对于状态的监控,就是对当前运行的task进行检测判断的过程。相应的代码如下,很清晰,参照文档看。

private boolean isInner() {boolean isInner = false;ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);List<RunningTaskInfo> info = manager.getRunningTasks(Integer.MAX_VALUE);String pkgName = info.get(0).topActivity.getPackageName();isInner = pkgName.startsWith(PKG_NAME_BASE);Log.d(TAG, "isInner() isInner = " + isInner);return isInner;}private boolean isHome() {boolean isHome = false;ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);List<RunningTaskInfo> info = manager.getRunningTasks(Integer.MAX_VALUE);isHome = homeLists.contains(info.get(0).topActivity.getPackageName());Log.d(TAG, "isHome() isHome = " + isHome);return isHome;}private List<String> getHomes() {List<String> packages = new ArrayList<String>();PackageManager packageManager = mServices.getPackageManager();Intent intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo info : resolveInfo) {packages.add(info.activityInfo.packageName);}return packages;}


二,注意事项

此部分,将列举出开发中所遇到的问题。

2-1 window的显示大小

假使window中添加的view为mContentView,影响window大小的最终参数只有:

mWindowLayoutParams.width = LinearLayout.LayoutParams.FILL_PARENT;
mWindowLayoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;


2-2 window的显示位置

定了坐标系之后,以下两个参数决定window的显示位置(以mContentView左上角为准)

mWindowLayoutParams.x = 0;
mWindowLayoutParams.y = mScreenHeight;// at the position of bottom


2-3 TouchEvent 和ClickEvent的冲突处理

核心是定义touch事件,滑动超过指定值时,才被识别为touch事件,否则则识别为click事件。这里需要深入的理解touch事件。

参看之前的日志。Android Touch事件分析

http://mikewang.blog.51cto.com/3826268/1204944

2-4 Service导致的Asynctask不能执行的问题。

在网上没有找到真正的原因,但是找到了解决方案。api level 11之后,Asynctask的默认模式从并行改为串行。即默认情况下,如果前一个task没有执行完,后一个task将会被阻塞。

可以通过手动设置Asynctask的模式来解决这个问题。

LoginAsyncTask task = new LoginAsyncTask(AccountManagementActivity.this);if (Utils.isHoneycombOrHigher()) {task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, sb.toString());} else {task.execute(sb.toString());}


三,实例

3-1 例子所涵盖的内容:

This demo will finish the functions as followings:
1, display the global floating view on the top of the screen.
2, switch the floating state(visible or invisible) when the user toggle from two of three state (app inner, other app, home).
3, dynamically change the floating view's size or position
4, let the floating view automatically on the edge of the screen (n/a)
5, handle the conflict between touch event and click event


3-2 demo 源码

github地址:https://github.com/mikewang0326/FloatingViewDemo

四,其他

4-1 开源项目

当自己参考网上的代码完成之后,发现xda上开源项目。但是花时间了解还是值得。以后如果再要做floating window相应的东西,可以直接使用这个开源库。

xda地址:http://forum.xda-developers.com/showthread.php?t=1688531

对应的介绍都有,源码在github上,从上述连接上都可以找到。

4-2 参考资料

主要参考了krislq的相关资料,很有帮助。附件给出文档。


http://www.coolblog.cn/news/9247f8b0445833b6.html

相关文章:

  • asp多表查询并显示_SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询
  • s7day2学习记录
  • 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架。
  • 矿Spring入门Demo
  • 拼音怎么写_老师:不会写的字用圈代替,看到孩子试卷,网友:人才
  • Linux 实时流量监测(iptraf中文图解)
  • Win10 + Python + GPU版MXNet + VS2015 + RTools + R配置
  • 美颜
  • shell访问php文件夹,Shell获取某目录下所有文件夹的名称
  • 如何优雅的实现 Spring Boot 接口参数加密解密?
  • LeCun亲授的深度学习入门课:从飞行器的发明到卷积神经网络
  • Mac原生Terminal快速登录ssh
  • java受保护的数据与_Javascript类定义语法,私有成员、受保护成员、静态成员等介绍...
  • mysql commit 机制_1024MySQL事物提交机制
  • 支撑微博千亿调用的轻量级RPC框架:Motan
  • jquery 使用小技巧
  • 2019-9
  • 法拉利虚拟学院2010 服务器,法拉利虚拟学院2010
  • vscode pylint 错误_将实际未错误的py库添加到pylint白名单
  • 科学计算工具NumPy(3):ndarray的元素处理
  • 工程师在工作电脑存 64G 不雅文件,被公司开除后索赔 41 万,结果…
  • linux批量创建用户和密码
  • newinsets用法java_Java XYPlot.setInsets方法代碼示例
  • js常用阻止冒泡事件
  • 气泡图在开源监控工具中的应用效果
  • 各类型土地利用图例_划重点!国土空间总体规划——土地利用
  • php 启动服务器监听
  • dubbo简单示例
  • 【设计模式】 模式PK:策略模式VS状态模式
  • [iptables]Redhat 7.2下使用iptables实现NAT
  • Ubuntu13.10:[3]如何开启SSH SERVER服务
  • CSS小技巧——CSS滚动条美化
  • JS实现-页面数据无限加载
  • 阿里巴巴分布式服务框架 Dubbo
  • 最新DOS大全
  • Django View(视图系统)
  • 阿里大鱼.net core 发送短信
  • 程序员入错行怎么办?
  • 两张超级大表join优化
  • 第九天函数
  • Linux软件安装-----apache安装
  • HDU 5988 最小费用流
  • Sorenson Capital:值得投资的 5 种 AI 技术
  • 《看透springmvc源码分析与实践》读书笔记一
  • 正式开课!如何学习相机模型与标定?(单目+双目+鱼眼+深度相机)
  • Arm芯片的新革命在缓缓上演
  • nagios自写插件—check_file
  • python3 错误 Max retries exceeded with url 解决方法
  • 行为模式之Template Method模式
  • 通过Spark进行ALS离线和Stream实时推荐