Android -- 桌面悬浮,QQ管家火箭实现
续上一篇博客《Android -- 桌面悬浮,仿360》,传送门:http://www.cnblogs.com/yydcdut/p/3909888.html,在此代码上继续添加实现。
比起普通的桌面悬浮窗,现在我们需要在拖动悬浮窗的时候将悬浮窗变成一个小火箭,并且在屏幕的底部添加一个火箭发射台。那么我们就从火箭发射台开始编写吧,首先创建launcher.xml作为火箭发射台的布局文件:
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView android:id="@+id/launcher_img" android:layout_width="200dp" android:layout_height="88dp" android:src="@drawable/launcher_bg_hold" /> </LinearLayout>
可以看到,这里的ImageView是用于显示当前火箭发射台状态的。我事先准备好了两张图片,一张是当小火箭未拖动到火箭发射台时显示的,一张是当小火箭拖动到火箭发射台上时显示的。
接下来创建RocketLauncher类,作为火箭发射台的View:
public class RocketLauncher extends LinearLayout { /** * 记录火箭发射台的宽度 */ public static int width; /** * 记录火箭发射台的高度 */ public static int height; /** * 火箭发射台的背景图片 */ private ImageView launcherImg; public RocketLauncher(Context context) { super(context); LayoutInflater.from(context).inflate(R.layout.launcher, this); launcherImg = (ImageView) findViewById(R.id.launcher_img); width = launcherImg.getLayoutParams().width; height = launcherImg.getLayoutParams().height; } /** * 更新火箭发射台的显示状态。如果小火箭被拖到火箭发射台上,就显示发射。 */ public void updateLauncherStatus(boolean isReadyToLaunch) { if (isReadyToLaunch) { launcherImg.setImageResource(R.drawable.launcher_bg_fire); } else { launcherImg.setImageResource(R.drawable.launcher_bg_hold); } } }
RocketLauncher中的代码还是非常简单的,在构建方法中调用了LayoutInflater的inflate()方法来将launcher.xml这个布局文件加载进来,并获取到了当前View的宽度和高度。在updateLauncherStatus()方法中会进行判断,如果传入的参数是true,就显示小火箭即将发射的图片,如果传入的是false,就显示将小火箭拖动到发射台的图片。
新增的文件只有这两个,剩下的就是要修改之前的代码了。首先修改MyWindowManager中的代码:
public class MyWindowManager { /** * 小悬浮窗View的实例 */ private static FloatWindowSmallView smallWindow; /** * 大悬浮窗View的实例 */ private static FloatWindowBigView bigWindow; /** * 火箭发射台的实例 */ private static RocketLauncher rocketLauncher; /** * 小悬浮窗View的参数 */ private static LayoutParams smallWindowParams; /** * 大悬浮窗View的参数 */ private static LayoutParams bigWindowParams; /** * 火箭发射台的参数 */ private static LayoutParams launcherParams; /** * 用于控制在屏幕上添加或移除悬浮窗 */ private static WindowManager mWindowManager; /** * 用于获取手机可用内存 */ private static ActivityManager mActivityManager; /** * 创建一个小悬浮窗。初始位置为屏幕的右部中间位置。 */ public static void createSmallWindow(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (smallWindow == null) { smallWindow = new FloatWindowSmallView(context); if (smallWindowParams == null) { smallWindowParams = new LayoutParams(); smallWindowParams.type = LayoutParams.TYPE_SYSTEM_ALERT; smallWindowParams.format = PixelFormat.RGBA_8888; smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE; smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP; smallWindowParams.width = FloatWindowSmallView.windowViewWidth; smallWindowParams.height = FloatWindowSmallView.windowViewHeight; smallWindowParams.x = screenWidth; smallWindowParams.y = screenHeight / 2; } smallWindow.setParams(smallWindowParams); windowManager.addView(smallWindow, smallWindowParams); } } /** * 将小悬浮窗从屏幕上移除。 */ public static void removeSmallWindow(Context context) { if (smallWindow != null) { WindowManager windowManager = getWindowManager(context); windowManager.removeView(smallWindow); smallWindow = null; } } /** * 创建一个大悬浮窗。位置为屏幕正中间。 */ public static void createBigWindow(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (bigWindow == null) { bigWindow = new FloatWindowBigView(context); if (bigWindowParams == null) { bigWindowParams = new LayoutParams(); bigWindowParams.x = screenWidth / 2 - FloatWindowBigView.viewWidth / 2; bigWindowParams.y = screenHeight / 2 - FloatWindowBigView.viewHeight / 2; bigWindowParams.type = LayoutParams.TYPE_PHONE; bigWindowParams.format = PixelFormat.RGBA_8888; bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP; bigWindowParams.width = FloatWindowBigView.viewWidth; bigWindowParams.height = FloatWindowBigView.viewHeight; } windowManager.addView(bigWindow, bigWindowParams); } } /** * 将大悬浮窗从屏幕上移除。 */ public static void removeBigWindow(Context context) { if (bigWindow != null) { WindowManager windowManager = getWindowManager(context); windowManager.removeView(bigWindow); bigWindow = null; } } /** * 创建一个火箭发射台,位置为屏幕底部。 */ public static void createLauncher(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (rocketLauncher == null) { rocketLauncher = new RocketLauncher(context); if (launcherParams == null) { launcherParams = new LayoutParams(); launcherParams.x = screenWidth / 2 - RocketLauncher.width / 2; launcherParams.y = screenHeight - RocketLauncher.height; launcherParams.type = LayoutParams.TYPE_PHONE; launcherParams.format = PixelFormat.RGBA_8888; launcherParams.gravity = Gravity.LEFT | Gravity.TOP; launcherParams.width = RocketLauncher.width; launcherParams.height = RocketLauncher.height; } windowManager.addView(rocketLauncher, launcherParams); } } /** * 将火箭发射台从屏幕上移除。 */ public static void removeLauncher(Context context) { if (rocketLauncher != null) { WindowManager windowManager = getWindowManager(context); windowManager.removeView(rocketLauncher); rocketLauncher = null; } } /** * 更新火箭发射台的显示状态。 */ public static void updateLauncher() { if (rocketLauncher != null) { rocketLauncher.updateLauncherStatus(isReadyToLaunch()); } } /** * 更新小悬浮窗的TextView上的数据,显示内存使用的百分比。 * * @param context * 可传入应用程序上下文。 */ public static void updateUsedPercent(Context context) { if (smallWindow != null) { TextView percentView = (TextView) smallWindow .findViewById(R.id.percent); percentView.setText(getUsedPercentValue(context)); } } /** * 是否有悬浮窗(包括小悬浮窗和大悬浮窗)显示在屏幕上。 * * @return 有悬浮窗显示在桌面上返回true,没有的话返回false。 */ public static boolean isWindowShowing() { return smallWindow != null || bigWindow != null; } /** * 判断小火箭是否准备好发射了。 * * @return 当火箭被发到发射台上返回true,否则返回false。 */ public static boolean isReadyToLaunch() { if ((smallWindowParams.x > launcherParams.x && smallWindowParams.x + smallWindowParams.width < launcherParams.x + launcherParams.width) && (smallWindowParams.y + smallWindowParams.height > launcherParams.y)) { return true; } return false; } /** * 如果WindowManager还未创建,则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。 * * @param context * 必须为应用程序的Context. * @return WindowManager的实例,用于控制在屏幕上添加或移除悬浮窗。 */ private static WindowManager getWindowManager(Context context) { if (mWindowManager == null) { mWindowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); } return mWindowManager; } /** * 如果ActivityManager还未创建,则创建一个新的ActivityManager返回。否则返回当前已创建的ActivityManager。 * * @param context * 可传入应用程序上下文。 * @return ActivityManager的实例,用于获取手机可用内存。 */ private static ActivityManager getActivityManager(Context context) { if (mActivityManager == null) { mActivityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); } return mActivityManager; } /** * 计算已使用内存的百分比,并返回。 * * @param context * 可传入应用程序上下文。 * @return 已使用内存的百分比,以字符串形式返回。 */ public static String getUsedPercentValue(Context context) { String dir = "/proc/meminfo"; try { FileReader fr = new FileReader(dir); BufferedReader br = new BufferedReader(fr, 2048); String memoryLine = br.readLine(); String subMemoryLine = memoryLine.substring(memoryLine .indexOf("MemTotal:")); br.close(); long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll( "\\D+", "")); long availableSize = getAvailableMemory(context) / 1024; int percent = (int) ((totalMemorySize - availableSize) / (float) totalMemorySize * 100); return percent + "%"; } catch (IOException e) { e.printStackTrace(); } return "悬浮窗"; } /** * 获取当前可用内存,返回数据以字节为单位。 * * @param context * 可传入应用程序上下文。 * @return 当前可用内存。 */ private static long getAvailableMemory(Context context) { ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); getActivityManager(context).getMemoryInfo(mi); return mi.availMem; } }
这里在代码中添加了一个isPressed标识位,用于判断用户是否正在拖动悬浮窗。当拖动的时候就调用updateViewStatus()方法来更新悬浮窗的显示状态,这时悬浮窗就会变成一个小火箭。然后当手指离开屏幕的时候,也会调用updateViewStatus()方法,这时发现isPressed为false,就会将悬浮窗重新显示出来。
同时,当手指离开屏幕的时候,还会调用MyWindowManager的isReadyToLaunch()方法来判断小火箭是否被拖动到火箭发射台上了,如果为true,就会触发火箭升空的动画效果。火箭升空的动画实现是写在LaunchTask这个任务里的,可以看到,这里会在doInBackground()方法中执行耗时逻辑,将小火箭的纵坐标不断减小,以让它实现上升的效果。当纵坐标减小到0的时候,火箭升空的动画就结束了,然后在onPostExecute()方法中重新将悬浮窗显示出来。
我是天王盖地虎的分割线
源代码:http://pan.baidu.com/s/1dD1Qx01
360进阶QQ管家火箭实现.zip
参考:http://blog.csdn.net/guolin_blog/article/details/16919859
Android -- 桌面悬浮,QQ管家火箭实现的更多相关文章
- Android仿腾讯手机管家实现桌面悬浮窗小火箭发射的动画效果
功能分析: 1.小火箭游离在activity之外,不依附于任何activity,不管activity是否开启,不影响小火箭的代码逻辑,所以小火箭的代码逻辑是要写在服务中: 2.小火箭挂载在手机窗体之上 ...
- android桌面悬浮窗仿QQ手机管家加速效果
主要还是用到了WindowManager对桌面悬浮进行管理. 需要一个火箭的悬浮窗 一个发射台悬浮窗 ,判断火箭是否放到了发射台,如果放上了,则使用AsyTask 慢慢将火箭的图片往上移.结束后., ...
- Android -- 桌面悬浮,仿360
实现原理 这种桌面悬浮窗的效果很类似与Wid ...
- Android 桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. 先谈一下基本的实现原理,这种桌面悬浮窗的效果很 ...
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
大家好,今天给大家带来一个仿360手机卫士悬浮窗效果的教程,在开始之前请允许我说几句不相干的废话. 不知不觉我发现自己接触Android已有近三个年头了,期间各种的成长少不了各位高手的帮助,总是有很多 ...
- Android桌面悬浮清内存app概述
今天闲来无事写了一个清内存的小东西,类似360,在桌面上悬浮,点击后清除后台无用程序,清除后台程序是通过调用ActivityManger.killBackgroundProcesses的方式来进行的, ...
- android桌面悬浮窗实现
首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. ...
- android桌面小火箭升空动画
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceS ...
- 简易的可拖动的桌面悬浮窗效果Demo
首先,我们需要知道,悬浮窗分为两种:Activity级别的悬浮窗,系统级别的悬浮窗 Activity级别的悬浮窗跟随所属Activity的生命周期而变化,而系统级别的悬浮窗则可以脱离Activity而 ...
随机推荐
- 用MsmqBinding投送message出现的一个灵异事件 【第二篇】
一直都在用Msmqbinding,也一直忽视了message里面的内容格式是什么样的,这也是微软给我们高层封装带给我们的开发效率,但同时一旦中间出了什么问题, 就不知道从何查起了.有个需求是这样的,服 ...
- SQL查询数据库中所有指定类型的字段名称和所在的表名
--查询数据库中所有指定类型的字段名称和所在的表名 --eg: 下面查的是当前数据库中 所有字段类型为 nvarchar(max) 的字段名和表名 SELECT cols.object_id , co ...
- 使用 xtrabackup 进行MySQL数据库物理备份
0. xtrabackup的功能 能实现的功能: 非阻塞备份innodb等事务引擎数据库. 备份myisam表会阻塞(需要锁). 支持全备.增量备份.压缩备份. 快速增量备份(xtradb,原理类似于 ...
- mysql学习笔记(一)
my建表操作 创建表 create Table <表名> ( 字段名1,数据类型 [列级约束] [默认值], 字段名2,数据类型 [列级约束] [默认值], ... [表级约束], [co ...
- 照片大管家iOS-实现本地相册、视频、安全保护、社交分享一站式功能,源码开放
<照片大管家> APP功能: 1.本地照片批量导入与编辑 2.本地视频存储与播放 3.手势密码.数字密码.TouchID安全保护 4.QQ.微信.微博.空间社交分享 5.其他细节功能. 运 ...
- iOS极光推送,两次Bundleid不一致( 开发证书没有通过验证 是否重新上传证书)的解决方案
极光在配置ios端推送时,需要上传p12证书,如果遇到如下图:: 证书上传未通过的原因一般有: 1.当前上传的p12证书密码输入有误: 2. 证书导出的时候展开了证书,把个人私钥导了出来,导证书的时候 ...
- 高性能MySQL笔记:第1章 MySQL架构
MySQL 最重要.最与众不同的特性是他的存储引擎架构,这种架构的设计将查询处理(Query Precessing)及其系统任务(Server Task)和数据的存储/提取相分离. 1.1 MyS ...
- nodejs学习资料
官方文档 阿里nodejs7天快速教程 从零开始nodejs系列文章 一个周末掌握IT前沿技术之node.js篇 nodejs中文api文档 nodejs中文api文档(0.12.2) node ...
- Keil代码中for循环延时问题
- 不就是抽个血吗,至于么-jQuery,Linux完结篇
hi 趁着周一去抽血化验,真开心...下午报告才出来,不过早上来了就开始各种晕菜,叫错名字,说错话.....至于么.. 还有在教研室的30天就可以肥家了,凯森凯森.今天不想干活(哪天想干过我就问问), ...