Android桌面悬浮窗
16lz
2021-01-24
这是一篇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
欢迎讨论,共同进步。
更多相关文章
- 关于安卓开发中Activity动画切换效果无效的一个总结
- Android之桌面组件App Widget初探
- Android中添加Admob广告(转
- android ApiDemos里的Transition3d翻转修复完善
- Android(安卓)在一个程序中启动另一个程序(包名,或者类名)
- Delphi XE开发 Android(安卓)开机自动启动
- Android开机自启动应用开发
- Android(安卓)图像存储在SD卡ContentResolver
- 初学Android,数据存储之SharedPreferences(四十一)