这是一篇Android悬浮窗的介绍,能够实现例如360,QQ管家那样的悬浮窗效果。后台运行了一个服务,用于控制在运行非桌面app情况下隐藏悬浮窗。



下面先上Demo截图:





上图就是所实现的简单悬浮窗示例,当然可以根据项目需要改变其相应布局。
给出Demo的源代码地址:http://download.csdn.net/detail/shinay/4450976


下面是创建悬浮窗的方法:

private boolean isAdded = false; // 是否已增加悬浮窗private static WindowManager wm;private static WindowManager.LayoutParams params;private Button btn_floatView;

/** * 创建悬浮窗 */private void createFloatView() {btn_floatView = new Button(getApplicationContext());        btn_floatView.setText("悬浮窗");                wm = (WindowManager) getApplicationContext()        .getSystemService(Context.WINDOW_SERVICE);        params = new WindowManager.LayoutParams();                // 设置window type        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;        /*         * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE;         * 那么优先级会降低一些, 即拉下通知栏不可见         */                params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明                // 设置Window flag        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL                              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;        /*         * 下面的flags属性的效果形同“锁定”。         * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。        wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL                               | LayoutParams.FLAG_NOT_FOCUSABLE                               | LayoutParams.FLAG_NOT_TOUCHABLE;         */                // 设置悬浮窗的长得宽        params.width = 100;        params.height = 100;                // 设置悬浮窗的Touch监听        btn_floatView.setOnTouchListener(new OnTouchListener() {        int lastX, lastY;        int paramX, paramY;        public boolean onTouch(View v, MotionEvent event) {switch(event.getAction()) {case MotionEvent.ACTION_DOWN:lastX = (int) event.getRawX();lastY = (int) event.getRawY();paramX = params.x;paramY = params.y;break;case MotionEvent.ACTION_MOVE:int dx = (int) event.getRawX() - lastX;int dy = (int) event.getRawY() - lastY;params.x = paramX + dx;params.y = paramY + dy;// 更新悬浮窗位置        wm.updateViewLayout(btn_floatView, params);break;}return true;}});                wm.addView(btn_floatView, params);        isAdded = true;}

做完这步,基本上就可以在桌面显示一个悬浮窗并且可以自由拖动了。

如果想要控制它在桌面显示,而进入到别的应用程序时隐藏它的话,就需要用一个后台运行的Service来实现了。

首先需要先获取到手机上的桌面程序的包名(桌面程序指的是按下HOME键所列出的程序,如go桌面等):
/**  * 获得属于桌面的应用的应用包名称  * @return 返回包含所有包名的字符串列表  */private List<String> getHomes() {List<String> names = new ArrayList<String>();      PackageManager packageManager = this.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 ri : resolveInfo) {          names.add(ri.activityInfo.packageName);      }    return names;  }

接着是判断当前运行的Activity是否为桌面应用程序,这里需要用到ActivityManager:
/**  * 判断当前界面是否是桌面  */  public boolean isHome(){  if(mActivityManager == null) {mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);  }    List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);      return homeList.contains(rti.get(0).topActivity.getPackageName());  }

有了上面两个方法,就可以实现这个功能了。只不过我们需要定时去判断,例如可以用一个Handler每一秒去检查一次:
private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch(msg.what) {case HANDLE_CHECK_ACTIVITY:if(isHome()) {if(!isAdded) {wm.addView(btn_floatView, params);isAdded = true;}} else {if(isAdded) {wm.removeView(btn_floatView);isAdded = false;}}mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);break;}}};

在我的Demo中,悬浮窗都是通过Service来控制的,那么我的启动与隐藏就都扔给Service处理就OK。
public void onClick(View v) {switch(v.getId()) {case R.id.btn_show:Intent show = new Intent(this, FloatingWindowService.class);show.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_SHOW);        startService(show);break;case R.id.btn_hide:Intent hide = new Intent(this, FloatingWindowService.class);hide.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_HIDE);        startService(hide);break;}}

在Service里的onStart方法中,只需要根据传过来的操作参数,对handler检查进行操作即可。
@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);switch(operation) {case OPERATION_SHOW:mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);break;case OPERATION_HIDE:mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);break;}}




另外:需要增加以下权限!!

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>    <uses-permission android:name="android.permission.GET_TASKS"/>





最后给出源代码地址: http://download.csdn.net/detail/shinay/4450976

欢迎讨论,共同进步。




更多相关文章

  1. 关于安卓开发中Activity动画切换效果无效的一个总结
  2. Android之桌面组件App Widget初探
  3. Android中添加Admob广告(转
  4. android ApiDemos里的Transition3d翻转修复完善
  5. Android(安卓)在一个程序中启动另一个程序(包名,或者类名)
  6. Delphi XE开发 Android(安卓)开机自动启动
  7. Android开机自启动应用开发
  8. Android(安卓)图像存储在SD卡ContentResolver
  9. 初学Android,数据存储之SharedPreferences(四十一)

随机推荐

  1. 【Android】图文解密Android WindowManag
  2. Android 保存和恢复activity的状态数据
  3. Android编译系统中的Android.bp、Bluepri
  4. Mac 下 Android Studio 获取SHA1 码
  5. Android相机开发中遇到的坑(注意事项)
  6. Android之Telephony各文件解释
  7. adb shell
  8. Android Screen Monitor使用
  9. xmlns的作用
  10. Handler+Messagequeue+looper