Window表示一个窗口的概念,在日常开发中直接接触Window的机会并不多,但却会经常用到Window,activity
、toast
、dialog
、PopupWindow
、状态栏等都是Window。在Android中Window是个抽象类,并且仅有一个实现类PhoneWindow
。
1、Window
Android中,Window有应用Window、子Window及系统Window三种类型,分别对应不同的层级范围,层级越高,显示越靠前,这里的“靠前”是指层级大的Window会覆盖在层级小的Window上面。
- 应用Window:对应层级范围是1~99,每个activity就对应一个应用Window,如果在activity中创建了一个应用Window,那么当跳转到另外一个Activity时,该Window会被覆盖。应用Window的高度不受状态栏影响。
- 子Window:对应层级范围是1000~1999,PopupWindow默认就是一个子Window(可以修改PopupWindow的Window类型),如果在activity中创建了一个子Window,那么当跳转到另外一个Activity时,该Window也会被覆盖。子Window的高度受状态栏影响。
- 系统Window:对应层级范围是2000~2999,
toast
、状态栏等都是系统Window,如果创建了一个系统Window,那么只有当该应用被销毁时,该Window才被会关闭(排除主动关闭),所以可以用系统Window实现像360那样的悬浮小球。系统Window需要设置<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
权限,否则会抛异常,在6.0以上需要动态申请。系统Window的高度不受状态栏影响。
前面说了Window的层级,下面就来看一个示例。
//代码参考了PopupWindow的源代码。
private void startWindow() {
//拿到activity中的wm对象,在attach中创建,是一个WindowManagerImpl对象
wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
frame = new PopupDecorView(this);
frame.setLayoutParams(new ActivityzhoLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
View view = View.inflate(this, R.layout.window_layout, null);
Button bt = view.findViewById(R.id.window_layout_button);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
//重新设置WindowManager.LayoutParams的值
WindowManager.LayoutParams p = createPopupLayoutParams(frame.getWindowToken());
frame.addView(view);
wm.addView(frame, p);
}
private LayoutParams createPopupLayoutParams(IBinder windowToken) {
final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
//设置Window gravity。gravity 表示居中,top表示位于顶部
p.gravity = Gravity.CENTER|Gravity.TOP;
p.flags = computeFlags(p.flags);
//设置Window的类型,其实这里我们也可以设置1~99、1000~1999、2000~2999之间的任意数字
p.type = LayoutParams.TYPE_APPLICATION;
//设置Window Token
p.token = windowToken;
//设置输入法模式
p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
//设置Window动画
p.windowAnimations = 0;
//设置Window像素格式
p.format = PixelFormat.TRANSLUCENT;
// Used for debugging.
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
//设置Window宽
p.width = LayoutParams.MATCH_PARENT;
//设置Window高
p.height = LayoutParams.WRAP_CONTENT;
return p;
}
private int computeFlags(int curFlags) {
curFlags &= ~(
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
WindowManager.LayoutParams.FLAG_SPLIT_TOUCH);
curFlags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
return curFlags;
}
//关闭Window
private void dismiss() {
wm.removeView(frame);
}
private class PopupDecorView extends FrameLayout {
public PopupDecorView(Context context) {
super(context);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (getKeyDispatcherState() == null) {
return super.dispatchKeyEvent(event);
}
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {