用过手机360和QQ手机管家等一些软件的朋友,会发现,在这些应用中,会出现一个悬浮窗体,例如QQ手机管家中打电话的场景:
这种窗体除了会显示外,还可以移动它的位置,并且一直显示。除了关闭当前程序外,窗口不会主动消失。其实,它的使用原理也很简单,就是借用了WindowManager这个管理类来实现的。
注意:要在AndroidManifest.xml中添加使用权限:
<uses-permission
android:name="android.permission.SYSTEM_ALERT_WINDOW" />
这里,我采用代码布局的方式,模仿了一下QQ这个界面效果:
import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class DesktopLayout extends LinearLayout {
public DesktopLayout(Context context) {
super(context);
setOrientation(LinearLayout.HORIZONTAL);
LayoutParams mLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
setLayoutParams(mLayoutParams);
// 显示的ICON
ImageView mImageView = new ImageView(context);
mImageView.setImageResource(R.drawable.icon);
addView(mImageView, mLayoutParams);
// 显示的文字
TextView mTextView = new TextView(context);
mTextView.setText("Hello");
mTextView.setTextSize(30);
addView(mTextView, mLayoutParams);
}
}
接下来,在activity中让它显示出来。首先要设置一下WindowManager.LayoutParams:
// 取得系统窗体
mWindowManager = (WindowManager) getApplicationContext()
.getSystemService("window");
// 窗体的布局样式
mLayoutParams = new WindowManager.LayoutParams();
// 设置窗体显示类型——TYPE_SYSTEM_ALERT(系统提示)
mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置窗体焦点及触摸:
// FLAG_NOT_FOCUSABLE(不能获得按键输入焦点)
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 设置显示的模式
mLayoutParams.format = PixelFormat.RGBA_8888;
// 设置对齐的方法
mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
// 设置窗体宽度和高度
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 设置窗体显示的位置,否则在屏幕中心显示
mLayoutParams.x = 50;
mLayoutParams.y = 50;
显示窗体与关闭窗体的方法:
mWindowManager.addView(mDesktopLayout, mLayoutParams);
mWindowManager.removeView(mDesktopLayout);
以下是activity的原代码,这里设计了一个双击关闭窗体的效果:
import android.app.Activity;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
public class DeskTip extends Activity {
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private DesktopLayout mDesktopLayout;
private long starttime;
/**
* 创建悬浮窗体
*/
private void createDesktopLayout() {
mDesktopLayout = new DesktopLayout(this);
mDesktopLayout.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
onActionMove(event);
return true;
}
});
}
/**
* 设置WindowManager
*/
private void createWindowManager() {
// 取得系统窗体
mWindowManager = (WindowManager) getApplicationContext()
.getSystemService("window");
// 窗体的布局样式
mLayoutParams = new WindowManager.LayoutParams();
// 设置窗体显示类型——TYPE_SYSTEM_ALERT(系统提示)
mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置窗体焦点及触摸:
// FLAG_NOT_FOCUSABLE(不能获得按键输入焦点)
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 设置显示的模式
mLayoutParams.format = PixelFormat.RGBA_8888;
// 设置对齐的方法
mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
// 设置窗体宽度和高度
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 设置窗体显示的位置,否则在屏幕中心显示
mLayoutParams.x = 50;
mLayoutParams.y = 50;
}
private void onActionMove(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long end = System.currentTimeMillis() - starttime;
// 双击的间隔在 200ms 到 500ms 之间
if (end > 200 && end < 500) {
closeDesk();
return;
}
starttime = System.currentTimeMillis();
}
mLayoutParams.x = (int) (event.getRawX() - (mDesktopLayout.getWidth()));
mLayoutParams.y = (int) (event.getRawY() - (mDesktopLayout.getHeight()));
mWindowManager.updateViewLayout(mDesktopLayout, mLayoutParams);
}
/**
* 显示DesktopLayout
*/
private void showDesk() {
mWindowManager.addView(mDesktopLayout, mLayoutParams);
finish();
}
/**
* 关闭DesktopLayout
*/
private void closeDesk() {
mWindowManager.removeView(mDesktopLayout);
finish();
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
createWindowManager();
createDesktopLayout();
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
showDesk();
}
});
}
}
显示的效果:

悬浮窗体例子