Window和WindowManager
Window表示一个窗口,可以实现在桌面上显示悬浮窗,Window是一个抽象类,具体实现是PhoneWindow。通过WindowManager创建Window,WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService,WindowManager和WindowManagerService交互是一个IPC过程,Window实际是View的直接管理者1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
val btn = Button(baseContext)
btn.text = "button"
btn.setOnClickListener { toast("Window Demo") }
val layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSLUCENT)
layoutParams.type = LayoutParams.TYPE_SYSTEM_OVERLAY/TYPE_SYSTEM_ERROR/TYPE_SYSTEM_OVERLAY/TYPE_APPLICATION_PANEL
//不需要获取焦点,不需要接收各种输入事件
layoutParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE
//window 区域以为的单击事件传递给底层window,当前window区域以内的自己处理,否则其他window无法收到单击事件
.or(LayoutParams.FLAG_NOT_TOUCH_MODAL)
//window 显示在锁屏上
.or(LayoutParams.FLAG_SHOW_WHEN_LOCKED)
layoutParams.gravity = Gravity.LEFT.or(Gravity.TOP)
layoutParams.x = 100
layoutParams.y = 300
windowManager.addView(btn, layoutParams)public interface WindowManager extends ViewManager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}添加触摸事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33val btn = Button(baseContext)
btn.isClickable = true
btn.text = "button"
// btn.setOnClickListener { toast("Window Demo") }
val layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSLUCENT)
// layoutParams.type = LayoutParams.TYPE_SYSTEM_OVERLAY
layoutParams.type =LayoutParams.TYPE_APPLICATION_PANEL
layoutParams.flags =
//不需要获取焦点,不需要接收各种输入事件
LayoutParams.FLAG_NOT_FOCUSABLE
//window 区域以为的单击事件传递给底层window,当前window区域以内的自己处理,否则其他window无法收到单击事件
.or(LayoutParams.FLAG_NOT_TOUCH_MODAL)
//window 显示在锁屏上
.or(LayoutParams.FLAG_SHOW_WHEN_LOCKED)
layoutParams.gravity = Gravity.LEFT.or(Gravity.TOP)
layoutParams.x = 100
layoutParams.y = 300
btn.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_MOVE -> {
layoutParams.x = event.rawX.toInt()
layoutParams.y = event.rawY.toInt()
windowManager.updateViewLayout(btn, layoutParams)
}
else -> {
Log.i("touch", "else")
}
}
return@setOnTouchListener false
}
windowManager.addView(btn, layoutParams)
Window内部机制
Window是抽象概念,每一个Window对应一个View和ViewRootImpl,以View的形式存在
- 接口
WindowManager
实现类WindowManagerImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}