WindowManager是窗口管理器, 所有显示窗口都可以通过它来控制
WindowManager.addView(view, layoutParams)
WindowManager.updateView(view, layoutParams)
WindowManager.removeView(view)
获取布局参数
WindowManager.LayoutParams params = getWindow().getAttributes()
;
|
创建布局参数
WindowManager.LayoutParams
params =
new WindowManager.LayoutParams();
|
用于确定窗口在屏幕上的显示层次
FIRST_APPLICATION_WINDOW
TYPE_BASE_APPLICATION
TYPE_APPLICATION
TYPE_APPLICATION_STARTING
LAST_APPLICATION_WINDOW
FIRST_SUB_WINDOW
TYPE_APPLICATION_PANEL
TYPE_APPLICATION_MEDIA
TYPE_APPLICATION_SUB_PANEL
TYPE_APPLICATION_ATTACHED_DIALOG
TYPE_APPLICATION_MEDIA_OVERLAY
TYPE_APPLICATION_ABOVE_SUB_PANEL
LAST_SUB_WINDOW
FIRST_SYSTEM_WINDOW
TYPE_STATUS_BAR
TYPE_SEARCH_BAR
TYPE_PHONE
TYPE_SYSTEM_ALERT
TYPE_KEYGUARD
TYPE_TOAST
TYPE_SYSTEM_OVERLAY
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_DIALOG
TYPE_KEYGUARD_DIALOG
TYPE_SYSTEM_ERROR
TYPE_INPUT_METHOD
TYPE_INPUT_METHOD_DIALOG
TYPE_WALLPAPER
TYPE_STATUS_BAR_PANEL
TYPE_SECURE_SYSTEM_OVERLAY
TYPE_DRAG
TYPE_STATUS_BAR_SUB_PANEL
TYPE_POINTER
TYPE_NAVIGATION_BAR
TYPE_VOLUME_OVERLAY
TYPE_BOOT_PROGRESS
TYPE_INPUT_CONSUMER
TYPE_DREAM
TYPE_NAVIGATION_BAR_PANEL
TYPE_DISPLAY_OVERLAY
TYPE_MAGNIFICATION_OVERLAY
TYPE_KEYGUARD_SCRIM
TYPE_PRIVATE_PRESENTATION
TYPE_VOICE_INTERACTION
TYPE_ACCESSIBILITY_OVERLAY
TYPE_VOICE_INTERACTION_STARTING
TYPE_DOCK_DIVIDER
TYPE_QS_DIALOG
TYPE_SCREENSHOT
用于确定窗口的行为
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
FLAG_DIM_BEHIND
FLAG_BLUR_BEHIND
FLAG_NOT_FOCUSABLE
FLAG_NOT_TOUCHABLE
FLAG_NOT_TOUCH_MODAL
FLAG_TOUCHABLE_WHEN_WAKING
FLAG_KEEP_SCREEN_ON
FLAG_LAYOUT_IN_SCREEN
FLAG_LAYOUT_NO_LIMITS
FLAG_FULLSCREEN
FLAG_FORCE_NOT_FULLSCREEN
FLAG_DITHER
FLAG_SECURE
FLAG_SCALED
FLAG_IGNORE_CHEEK_PRESSES
FLAG_LAYOUT_INSET_DECOR
FLAG_ALT_FOCUSABLE_IM
FLAG_WATCH_OUTSIDE_TOUCH
FLAG_SHOW_WHEN_LOCKED
FLAG_SHOW_WALLPAPER
FLAG_TURN_SCREEN_ON
FLAG_DISMISS_KEYGUARD
FLAG_SPLIT_TOUCH
FLAG_HARDWARE_ACCELERATED
FLAG_LAYOUT_IN_OVERSCAN
FLAG_TRANSLUCENT_STATUS
FLAG_TRANSLUCENT_NAVIGATION
FLAG_LOCAL_FOCUS_MODE
FLAG_SLIPPERY
FLAG_LAYOUT_ATTACHED_IN_DECOR
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
用于确定窗口和输入法之间的关系
SOFT_INPUT_MASK_STATE
SOFT_INPUT_STATE_UNSPECIFIED
SOFT_INPUT_STATE_UNCHANGED
SOFT_INPUT_STATE_HIDDEN
SOFT_INPUT_STATE_ALWAYS_HIDDEN
SOFT_INPUT_STATE_VISIBLE
SOFT_INPUT_STATE_ALWAYS_VISIBLE
SOFT_INPUT_MASK_ADJUST
SOFT_INPUT_ADJUST_UNSPECIFIED
SOFT_INPUT_ADJUST_RESIZE
SOFT_INPUT_ADJUST_PAN
SOFT_INPUT_ADJUST_NOTHING
SOFT_INPUT_IS_FORWARD_NAVIGATION
用于确定窗口的方向
SCREEN_ORIENTATION_UNSPECIFIED
SCREEN_ORIENTATION_LANDSCAPE
SCREEN_ORIENTATION_PORTRAIT
SCREEN_ORIENTATION_REVERSE_LANDSCAPE
SCREEN_ORIENTATION_REVERSE_PORTRAIT
SCREEN_ORIENTATION_SENSOR
SCREEN_ORIENTATION_NOSENSOR
SCREEN_ORIENTATION_SENSOR_LANDSCAPE
SCREEN_ORIENTATION_SENSOR_PORTRAIT
SCREEN_ORIENTATION_FULL_SENSOR
SCREEN_ORIENTATION_USER
SCREEN_ORIENTATION_USER_LANDSCAPE
SCREEN_ORIENTATION_USER_PORTRAIT
SCREEN_ORIENTATION_FULL_USER
SCREEN_ORIENTATION_BEHIND
SCREEN_ORIENTATION_LOCKED
锁定当前方向
获取当前方向
int mCurrentOrientation = getResources().getConfiguration().orientation;
|
用于确定屏幕旋转时的动画. 是否有效取决于手机
ROTATION_ANIMATION_JUMPCUT
ROTATION_ANIMATION_CROSSFADE
ROTATION_ANIMATION_ROTATE
ROTATION_ANIMATION_CHANGED
窗口下层变暗程度, 默认1.0f不变暗
0.0f~1.0f
设置按键的亮度. 有些手机没有键盘灯的无效
0.0f~1.0f
屏幕亮度
默认是负数, 表示跟随系统亮度
0.0f~1.0f表示最暗到最亮
设置系统界面的可见性. 是否有效和手机系统有关
View.INVISIBLE
View.SYSTEM_UI_FLAG_LOW_PROFILE
悬浮窗主要是设置type, 有多种type都可以实现悬浮窗效果(PHONE, SYSTEM_ALERT…)
WindowManager mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
// 创建一个新的布局
WindowManager.LayoutParams
param = new WindowManager.LayoutParams();
// 设置窗口属性
param.
type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置为系统警告窗, 可以悬浮在其他应用之上
param.
format = PixelFormat.TRANSLUCENT;
// 支持透明
param.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
// 可在全屏幕布局, 不受状态栏影响
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 最初不可获取焦点, 这样不影响底层应用接收触摸事件
param.alpha =
0.9f;
// 悬浮窗的透明度
param.gravity = Gravity.LEFT | Gravity.TOP;
// 悬浮窗的重力效果
param.width = dp2px(
140);
// 悬浮窗宽度
param.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 悬浮窗高度
// 以下将悬浮穿定位在屏幕中央
int screenWidth = mWindowManager.getDefaultDisplay().getWidth();
int screenHeight = mWindowManager.getDefaultDisplay().getHeight();
param.x = (screenWidth -
param.width) /
2;
param.y = (screenHeight -
param.height) /
2;
// 创建悬浮窗view
mFloatView = View.inflate(this, R.layout.view_float_window, null);
ButterKnife.bind(this, mFloatView);
// 添加到屏幕
mWindowManager.addView(mFloatView,
param);
|
悬浮窗如果需要弹出输入法进行输入, 就需要获取焦点
比如在悬浮窗中没有EditText时, 使用FLAG_NOT_FOCUSABLE禁止获取焦点, 这样背景window就可以操作, 可以输入, 可以使用按键
当输入法和悬浮窗输入窗口重叠时, 有两种处理方式, 都是通过param.softInputMode
来实现:
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
为悬浮窗设置onTouchListener, 通过事件判断是点击还是移动
使用mWindowManager.updateViewLayout(mFloatView, param)
来更新窗口位置
floatView.setOnTouchListener(
new View.OnTouchListener() {
// 记录上次移动的位置
private
float lastX =
0;
private
float lastY =
0;
// 是否是移动事件
boolean isMoved =
false;
@
Override
public boolean
onTouch(
View v, MotionEvent event) {
switch (
event.getAction()) {
case MotionEvent.ACTION_DOWN:
isMoved =
false;
// 记录按下位置
lastX =
event.getRawX();
lastY =
event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
isMoved =
true;
// 记录移动后的位置
float moveX =
event.getRawX();
float moveY =
event.getRawY();
// 获取当前窗口的布局属性, 添加偏移量, 并更新界面, 实现移动
WindowManager.LayoutParams param = (WindowManager.LayoutParams) mFloatView.getLayoutParams();
param.x += (
int) (moveX - lastX);
param.y += (
int) (moveY - lastY);
mWindowManager.updateViewLayout(mFloatView, param);
lastX = moveX;
lastY = moveY;
case MotionEvent.ACTION_CANCEL:
isMoved =
true;
break;
}
// 如果是移动事件, 则消费掉; 如果不是, 则由其他处理, 比如点击
return isMoved;
}
});
|
android:configChanges="orientation|screenSize"
keyboardHidden
orientation
screenSize
orientation|screenSize: 改变屏幕方向时并不重启Activity
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
|
getWindow()
.addFlags(
WindowManager
.LayoutParams
.FLAG_FULLSCREEN);
|
getWindow()
.setAttributes(windowParams);
|