这是一篇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;
}
/**
* 获得属于桌面的应用的应用包名称
* @return 返回包含所有包名的字符串列表
*/
private List getHomes() {
List names = new ArrayList();
PackageManager packageManager = this.getPackageManager();
// 属性
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for(ResolveInfo ri : resolveInfo) {
names.add(ri.activityInfo.packageName);
}
return names;
}
/**
* 判断当前界面是否是桌面
*/
public boolean isHome(){
if(mActivityManager == null) {
mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
}
List rti = mActivityManager.getRunningTasks(1);
return homeList.contains(rti.get(0).topActivity.getPackageName());
}
private Handler mHandler = new Handler() {
@Override
public 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;
}
}
};
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;
}
}
@Override
public 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;
}
}
另外:需要增加以下权限!!