java.lang.Object | ||
? | android.view.ViewGroup.LayoutParams | |
? | android.view.WindowManager.LayoutParams |
int | FLAGS_CHANGED | 用于表示flags发生了变化,关于此的详细内容请看后文。 |
int | FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | Window flag: as long as this window is visible to the user, allow the lock screen to activate while the screen is on. 当该window对用户可见的时候,允许锁屏。 |
int | FLAG_ALT_FOCUSABLE_IM | Window flag: invert the state of FLAG_NOT_FOCUSABLE with respect to how this window interacts with the current method. |
int | FLAG_BLUR_BEHIND | Window flag: blur everything behind this window. 让该window后所有东西都模糊(blur) |
int | FLAG_DIM_BEHIND | Window flag: everything behind this window will be dimmed. 让该window后所有的东西都成暗淡(dim) |
int | FLAG_DISMISS_KEYGUARD | Window flag: when set the window will cause the keyguard to be dismissed, only if it is not a secure lock keyguard. |
int | FLAG_DITHER | Window flag: turn on dithering when compositing this window to the screen. 开启抖动(dithering) |
int | FLAG_FORCE_NOT_FULLSCREEN | Window flag: Override {@link #FLAG_FULLSCREEN and force the screen decorations (such as status bar) to be shown. 恢复window非全屏显示 |
int | FLAG_FULLSCREEN | Window flag: Hide all screen decorations (e.g. 让window进行全屏显示 |
int | FLAG_HARDWARE_ACCELERATED | Indicates whether this window should be hardware accelerated. 对该window进行硬件加速. 该flag必须在设置你的Activity或Dialog的Content View之前进行设置, 而且如果你在mainfest文件中用Android:hardwareAccelerated开启了该属性的话,那么你在程序中就不能再改变它。mainfest文件中android:hardwareAccelerated属性默认是开启的("true")。 |
int | FLAG_IGNORE_CHEEK_PRESSES | Window flag: intended for windows that will often be used when the user is holding the screen against their face, it will aggressively filter the event stream to prevent unintended presses in this situation that may not be desired for a particular window, when such an event stream is detected, the application will receive a CANCEL motion event to indicate this so applications can handle this accordingly by taking no action on the event until the finger is released. |
int | FLAG_KEEP_SCREEN_ON | Window flag: as long as this window is visible to the user, keep the device's screen turned on and bright. 当该window对用户可见时,让设备屏幕处于高亮(bright)状态。 |
int | FLAG_LAYOUT_INSET_DECOR | Window flag: a special option only for use in combination with FLAG_LAYOUT_IN_SCREEN . |
int | FLAG_LAYOUT_IN_SCREEN | Window flag: place the window within the entire screen, ignoring decorations around the border (a.k.a. 让window占满整个手机屏幕,不留任何边界(border) |
int | FLAG_LAYOUT_NO_LIMITS | Window flag: allow window to extend outside of the screen. window大小不再不受手机屏幕大小限制,即window可能超出屏幕之外,这时部分内容在屏幕之外。 |
int | FLAG_NOT_FOCUSABLE | Window flag: this window won't ever get key input focus, so the user can not send key or other button events to it. 让window不能获得焦点,这样用户快就不能向该window发送按键事件及按钮事件 |
int | FLAG_NOT_TOUCHABLE | Window flag: this window can never receive touch events. 让该window不接受触摸屏事件 |
int | FLAG_NOT_TOUCH_MODAL | Window flag: Even when this window is focusable (its {@link #FLAG_NOT_FOCUSABLE is not set), allow any pointer events outside of the window to be sent to the windows behind it. 即使在该window在可获得焦点情况下,仍然把该window之外的任何event发送到该window之后的其他window. |
int | FLAG_SCALED | Window flag: a special mode where the layout parameters are used to perform scaling of the surface when it is composited to the screen. |
int | FLAG_SECURE | Window flag: don't allow screen shots while this window is displayed. 当该window在进行显示的时候,不允许截屏。 |
int | FLAG_SHOW_WALLPAPER | Window flag: ask that the system wallpaper be shown behind your window. 在该window后显示系统的墙纸(wallpaper) |
int | FLAG_SHOW_WHEN_LOCKED | Window flag: special flag to let windows be shown when the screen is locked. 当锁屏的时候,显示该window. |
int | FLAG_SPLIT_TOUCH | Window flag: when set the window will accept for touch events outside of its bounds to be sent to other windows that also support split touch. When this flag is not set, the first pointer that goes down determines the window to which all subsequent touches go until all pointers go up. When this flag is set, each pointer (not necessarily the first) that goes down determines the window to which all subsequent touches of that pointer will go until that pointer goes up thereby enabling touches with multiple pointers to be split across multiple windows 当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch. |
int | FLAG_TOUCHABLE_WHEN_WAKING | Window flag: When set, if the device is asleep when the touch screen is pressed, you will receive this first touch event. 当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到到事件 |
int | FLAG_TURN_SCREEN_ON | Window flag: when set as a window is being added or made visible, once the window has been shown then the system will poke the power manager's user activity (as if the user had woken up the device) to turn the screen on. 当然window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕。 |
int | FLAG_WATCH_OUTSIDE_TOUCH | Window flag: if you have set FLAG_NOT_TOUCH_MODAL , you can set this flag to receive a single special MotionEvent with the action MotionEvent.ACTION_OUTSIDE for touches that occur outside of your window. 如果你设置了该flag,那么在你FLAG_NOT_TOUNCH_MODAL的情况下,即使触摸屏事件发送在该window之外,其事件被发送到了后面的window,那么该window仍然将以MotionEvent.ACTION_OUTSIDE形式收到该触摸屏事件 |
int |
SOFT_INPUT_ADJUST_NOTHING |
Adjustment option for softInputMode: set to have a window not adjust for a shown input method. |
|
int |
SOFT_INPUT_ADJUST_PAN
|
Adjustment option for softInputMode: set to have a window pan when an input method is shown, so it doesn't need to deal with resizing but just panned by the framework to ensure the current input focus is visible. 即使调整空白区域,软键盘还是有可能遮挡一些有内容区域, 这时用户就只有退出软键盘才能看到这些被遮挡区域并进行交互。
|
|
int |
SOFT_INPUT_ADJUST_RESIZE |
Adjustment option for softInputMode: set to allow the window to be resized when an input method is shown, so that its contents are not covered by the input method. 这样的话控件可能会变形。 |
|
int |
SOFT_INPUT_ADJUST_UNSPECIFIED |
Adjustment option for softInputMode: nothing specified. |
|
int |
SOFT_INPUT_IS_FORWARD_NAVIGATION |
Bit for softInputMode: set when the user has navigated forward to the window. |
|
int |
SOFT_INPUT_MASK_ADJUST |
Mask for softInputMode of the bits that determine the way that the window should be adjusted to accommodate the soft input window. SOFT_INPUT_ADJUST_NOTHING, SOFT_INPUT_ADJUST_PAN, SOFT_INPUT_ADJUST_RESIZE, SOFT_INPUT_ADJUST_UNSPECIFIED。 SOFT_INPUT_STATE_ALWAYS_HIDDEN, SOFT_INPUT_STATE_ALWAYS_VISIBLE, SOFT_INPUT_STATE_VISIBLE, SOFT_INPUT_STATE_UNSPECIFIED之一 |
|
int |
SOFT_INPUT_MASK_STATE |
Mask for softInputMode of the bits that determine the desired visibility state of the soft input area for this window. |
|
int |
SOFT_INPUT_MODE_CHANGED |
用于表示softInputMode发生了变化。关于此的详细内容请看后文。 |
|
int |
SOFT_INPUT_STATE_ALWAYS_HIDDEN |
Visibility state for softInputMode: focus. |
|
int |
SOFT_INPUT_STATE_ALWAYS_VISIBLE |
Visibility state for softInputMode: receives input focus. |
|
int |
SOFT_INPUT_STATE_HIDDEN |
Visibility state for softInputMode: the user is navigating forward to your window). |
|
int |
SOFT_INPUT_STATE_UNCHANGED |
Visibility state for softInputMode: please don't change the state of the soft input area. |
|
int |
SOFT_INPUT_STATE_UNSPECIFIED |
Visibility state for softInputMode: no state has been specified. |
|
int |
SOFT_INPUT_STATE_VISIBLE |
Visibility state for softInputMode: please show the soft input area when normally appropriate |
int | TYPE_APPLICATION | Window type: a normal application window. 普通的应用程序window,token必须设置为Activity的token,以指出该窗口属谁 |
int | TYPE_APPLICATION_ATTACHED_DIALOG | Window type: like TYPE_APPLICATION_PANEL , but layout of the window happens as that of a top-level window, not as a child of its container.对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。 |
int | TYPE_APPLICATION_MEDIA | Window type: window for showing media (e.g. 媒体窗口,例如视频。显示于宿主窗口下层。 |
int | TYPE_APPLICATION_PANEL | Window type: a panel on top of an application window. 面板窗口,显示于宿主窗口上层 |
int | TYPE_APPLICATION_STARTING | Window type: special application window that is displayed while the application is starting. 用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。它用于让系统显示些信息,直到应用程序可以开启自己的窗口 |
int | TYPE_APPLICATION_SUB_PANEL | Window type: a sub-panel on top of an application window. 应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上) |
int | TYPE_BASE_APPLICATION | Window type: an application window that serves as the "base" window of the overall application; all other application windows will appear on top of it. 所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。 |
int | TYPE_CHANGED | 表示window的类型发生了变化,关于此的详细内容请看后文。 |
int | TYPE_INPUT_METHOD | Window type: internal input methods windows, which appear above the normal UI. 内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖 |
int | TYPE_INPUT_METHOD_DIALOG | Window type: internal input methods dialog windows, which appear above the current input method window. 内部输入法对话框,显示于当前输入法窗口之上 |
int | TYPE_KEYGUARD | Window type: keyguard window. 锁屏窗口 |
int | TYPE_KEYGUARD_DIALOG | Window type: dialogs that the keyguard shows 锁屏时显示的对话框 |
int | TYPE_PHONE | Window type: phone. 电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。 |
int | TYPE_PRIORITY_PHONE | Window type: priority phone UI, which needs to be displayed even if the keyguard is active. 电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。 |
int | TYPE_SEARCH_BAR | Window type: the search bar. 搜索栏。只能有一个搜索栏;它位于屏幕上方。 |
int | TYPE_STATUS_BAR | Window type: the status bar. 状态栏类型的window。只能有一个状态栏window;它位于屏幕顶端,其他窗口都位于它下方。 |
int | TYPE_STATUS_BAR_PANEL | Window type: panel that slides out from over the status bar 状态栏的滑动面板 |
int | TYPE_SYSTEM_ALERT | Window type: system window, such as low power alert. 系统提示window,比如电池低的警告。它总是出现在应用程序窗口之上。 |
int | TYPE_SYSTEM_DIALOG | Window type: panel that slides out from the status bar 系统对话框。(例如音量调节框) |
int | TYPE_SYSTEM_ERROR | Window type: internal system error windows, appear on top of everything they can. 系统内部错误提示,显示于所有内容之上 |
int | TYPE_SYSTEM_OVERLAY | Window type: system overlay windows, which need to be displayed on top of everything else. 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。 |
int | TYPE_TOAST | Window type: transient notifications. toast类型的window |
int | TYPE_WALLPAPER | Window type: wallpaper window, placed behind any window that wants to sit on top of the wallpaper. 用于墙纸的window |
int | FIRST_APPLICATION_WINDOW | Start of window types that represent normal application windows. Constant Value: 1 (0x00000001) |
int | FIRST_SUB_WINDOW | Start of types of sub-windows. Constant Value: 1000 (0x000003e8) |
int | FIRST_SYSTEM_WINDOW | Start of system-specific window types. Constant Value: 2000 (0x000007d0) |
int | LAST_APPLICATION_WINDOW | End of types of application windows. Constant Value: 99 (0x00000063) |
int | LAST_SUB_WINDOW | End of types of sub-windows. Constant Value: 1999 (0x000007cf) |
int | LAST_SYSTEM_WINDOW | End of types of system windows. Constant Value: 2999 (0x00000bb7) |
float | BRIGHTNESS_OVERRIDE_FULL | Value for screenBrightness and buttonBrightness indicating that the screen or button backlight brightness should be set to the hightest value when this window is in front. 把brightness(screenBrightness/buttonBrightness)设置到最高值。 |
float | BRIGHTNESS_OVERRIDE_NONE | Default value for screenBrightness and buttonBrightness indicating that the brightness value is not overridden for this window and normal brightness policy should be used.不对brightness(screenBrightness/buttonBrightness)重新进行设置,采用默认的普通值。 |
float | BRIGHTNESS_OVERRIDE_OFF | Value for screenBrightness and buttonBrightness indicating that the screen or button backlight brightness should be set to the lowest value when this window is in front.把brightness(screenBrightness/buttonBrightness)设置到最低值。 |
int | ALPHA_CHANGED | 用于表示成员变量alpha是否被改变 |
int | ANIMATION_CHANGED | 用于表示成员变量windowAnimations是否被改变 |
int | DIM_AMOUNT_CHANGED | 用于表示成员变量dimAmount是否被改变 |
int | FLAGS_CHANGED | 用于表示成员变量flags是否被改变 |
int | LAYOUT_CHANGED | 用于表示layout是否被改变.这里的layout是指以下变量所包含的信息: width,height,x,y, verticalMargin,verticalWeight,horizontalMargin,horizontalWeight |
int | SCREEN_BRIGHTNESS_CHANGED | 用于表示brightness是否被改变. 这里的brightness是指以下变量对应的信息:screenBrightness,buttonBrightness |
int | SCREEN_ORIENTATION_CHANGED | 用于表示成员变量screenOrientation是否被改变 |
int | SOFT_INPUT_MODE_CHANGED | 用于表示成员变量softInputMode是否被改变 |
int | TITLE_CHANGED | 用于表示成员变量title是否被改变 |
int | TYPE_CHANGED | 用于表示成员变量type是否被改变 |
int | FORMAT_CHANGED | Constant Value: 8 (0x00000008) 用于表示成员变量format是否被改变 |
public int | height | Information about how tall the view wants to be. |
public LayoutAnimationController.AnimationParameters | layoutAnimationParameters | Used to animate layouts. |
public int | width | Information about how wide the view wants to be. |
public static final Creator< WindowManager.LayoutParams> | CREATOR | |
public float | alpha | An alpha value to apply to this entire window. |
public float | buttonBrightness | This can be used to override the standard behavior of the button and keyboard backlights. |
public float | dimAmount | When FLAG_DIM_BEHIND is set, this is the amount of dimming to apply. |
public int | flags | Various behavioral options/flags. |
public int | format | The desired bitmap format. |
public int | gravity | Placement of window within the screen as per Gravity . |
public float | horizontalMargin | The horizontal margin, as a percentage of the container's width, between the container and the widget. |
public float | horizontalWeight | Indicates how much of the extra space will be allocated horizontally to the view associated with these LayoutParams. |
public int | memoryType | This field is deprecated. this is ignored |
public String | packageName | Name of the package owning this window. |
public float | screenBrightness | This can be used to override the user's preferred brightness of the screen. |
public int | screenOrientation | Specific orientation value for a window. |
public int | softInputMode | Desired operating mode for any soft input area. |
public int | systemUiVisibility | Control the visibility of the status bar. |
public IBinder | token | Identifier for this window. |
public int | type | The general type of window. |
public float | verticalMargin | The vertical margin, as a percentage of the container's height, between the container and the widget. |
public float | verticalWeight | Indicates how much of the extra space will be allocated vertically to the view associated with these LayoutParams. |
public int | windowAnimations | A style resource defining the animations to use for this window. |
public int | x | X position for this window. |
public int | y | Y position for this window. |
ublic Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
final int | copyFrom( WindowManager.LayoutParams o) | ||||||||||
String | debug( String output)
Returns a String representation of this set of layout parameters.
|
||||||||||
int | describeContents()
Describe the kinds of special objects contained in this Parcelable's marshalled representation.
|
||||||||||
final CharSequence | getTitle() | ||||||||||
static boolean | mayUseInputMethod(int flags)
Given a particular set of window manager flags, determine whether such a window may be a target for an input method when it has focus.
|
||||||||||
final void | setTitle( CharSequence title) | ||||||||||
String | toString()
Returns a string containing a concise, human-readable description of this object.
|
||||||||||
void | writeToParcel( Parcel out, int parcelableFlags)
Flatten this object in to a Parcel.
|
通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager
对象。
每一个WindowManager对象都和一个特定的 Display
绑定。
想要获取一个不同的display的WindowManager,可以用 createDisplayContext(Display)
来获取那个display的 Context
,之后再使用:
Context.getSystemService(Context.WINDOW_SERVICE)来获取WindowManager。
使用WindowManager可以在其他应用最上层,甚至手机桌面最上层显示窗口。
调用的是WindowManager继承自基类的addView方法和removeView方法来显示和隐藏窗口。具体见后面的实例。
另:API 17推出了Presentation
,它将自动获取display的Context和WindowManager,可以方便地在另一个display上显示窗口。
声明权限
首先在manifest中添加如下权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
注意:在MIUI上需要在设置中打开本应用的”显示悬浮窗”开关,并且重启应用,否则悬浮窗只能显示在本应用界面内,不能显示在手机桌面上。
服务获取和基本参数设置
// 获取应用的Context mContext = context.getApplicationContext(); // 获取WindowManager mWindowManager = (WindowManager) mContext .getSystemService(Context.WINDOW_SERVICE);
参数设置:
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); // 类型 params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT // 设置flag int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件 params.flags = flags; // 不设置这个弹出框的透明遮罩显示为黑色 params.format = PixelFormat.TRANSLUCENT; // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按 // 不设置这个flag的话,home页的划屏会有问题 params.width = LayoutParams.MATCH_PARENT; params.height = LayoutParams.MATCH_PARENT; params.gravity = Gravity.CENTER;
点击和按键事件
除了View中的各个控件的点击事件之外,弹窗View的消失控制需要一些处理。
点击弹窗外部可隐藏弹窗的效果,首先,悬浮窗是全屏的,只不过最外层的是透明或者半透明的:
布局如下:
xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:background="@color/darken_background" android:gravity="center" android:orientation="vertical" > <RelativeLayout android:id="@+id/popup_window" android:layout_width="@dimen/dialog_window_width" android:layout_height="@dimen/dialog_window_height" android:background="@color/white" android:orientation="vertical" > <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="@dimen/dialog_title_height" android:gravity="center" android:text="@string/default_title" android:textColor="@color/dialog_title_text_color" android:textSize="@dimen/dialog_title_text_size" /> <View android:id="@+id/title_divider" android:layout_width="match_parent" android:layout_height="2dp" android:layout_below="@id/title" android:background="@drawable/dialog_title_divider" /> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/title_divider" android:gravity="center" android:padding="@dimen/dialog_content_padding_side" android:text="@string/default_content" android:textColor="@color/dialog_content_text_color" android:textSize="@dimen/dialog_content_text_size" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:paddingBottom="@dimen/dialog_content_padding_bottom" android:paddingLeft="@dimen/dialog_content_padding_side" android:paddingRight="@dimen/dialog_content_padding_side" > <Button android:id="@+id/negativeBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:background="@drawable/promote_window_negative_btn_selector" android:focusable="true" android:padding="@dimen/dialog_button_padding" android:text="@string/default_btn_cancel" android:textColor="@color/dialog_negative_btn_text_color" android:textSize="@dimen/dialog_button_text_size" /> <Button android:id="@+id/positiveBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="18dp" android:layout_weight="1" android:background="@drawable/promote_window_positive_btn_selector" android:focusable="true" android:padding="@dimen/dialog_button_padding" android:text="@string/default_btn_ok" android:textColor="@color/dialog_positive_btn_text_color" android:textSize="@dimen/dialog_button_text_size" /> LinearLayout> RelativeLayout> LinearLayout>
点击外部可消除设置:
// 点击窗口外部区域可消除 // 这点的实现主要将悬浮窗设置为全屏大小,外层有个透明背景,中间一部分视为内容区域 // 所以点击内容区域外部视为点击悬浮窗外部 final View popupWindowView = view.findViewById(R.id.popup_window);// 非透明的内容区域 view.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { LogUtil.i(LOG_TAG, "onTouch"); int x = (int) event.getX(); int y = (int) event.getY(); Rect rect = new Rect(); popupWindowView.getGlobalVisibleRect(rect); if (!rect.contains(x, y)) { WindowUtils.hidePopupWindow(); } LogUtil.i(LOG_TAG, "onTouch : " + x + ", " + y + ", rect: " + rect); return false; } });
点击Back键可隐藏弹窗:
注意Flag不能设置WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE。
// 点击back键可消除 view.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: WindowUtils.hidePopupWindow(); return true; default: return false; } } });
完整效果
完整代码:
package com.example.hellowindow; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Handler mHandler = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler = new Handler(); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mHandler.postDelayed(new Runnable() { @Override public void run() { WindowUtils.showPopupWindow(MainActivity.this); } }, 1000 * 3); } }); } }
package com.example.hellowindow; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnKeyListener; import android.view.View.OnTouchListener; import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.WindowManager.LayoutParams; import android.widget.Button; /** * 弹窗辅助类 * * @ClassName WindowUtils * * */ public class WindowUtils { private static final String LOG_TAG = "WindowUtils"; private static View mView = null; private static WindowManager mWindowManager = null; private static Context mContext = null; public static Boolean isShown = false; /** * 显示弹出框 * * @param context * @param view */ public static void showPopupWindow(final Context context) { if (isShown) { LogUtil.i(LOG_TAG, "return cause already shown"); return; } isShown = true; LogUtil.i(LOG_TAG, "showPopupWindow"); // 获取应用的Context mContext = context.getApplicationContext(); // 获取WindowManager mWindowManager = (WindowManager) mContext .getSystemService(Context.WINDOW_SERVICE); mView = setUpView(context); final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); // 类型 params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT // 设置flag int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件 params.flags = flags; // 不设置这个弹出框的透明遮罩显示为黑色 params.format = PixelFormat.TRANSLUCENT; // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按 // 不设置这个flag的话,home页的划屏会有问题 params.width = LayoutParams.MATCH_PARENT; params.height = LayoutParams.MATCH_PARENT; params.gravity = Gravity.CENTER; mWindowManager.addView(mView, params); LogUtil.i(LOG_TAG, "add view"); } /** * 隐藏弹出框 */ public static void hidePopupWindow() { LogUtil.i(LOG_TAG, "hide " + isShown + ", " + mView); if (isShown && null != mView) { LogUtil.i(LOG_TAG, "hidePopupWindow"); mWindowManager.removeView(mView); isShown = false; } } private static View setUpView(final Context context) { LogUtil.i(LOG_TAG, "setUp view"); View view = LayoutInflater.from(context).inflate(R.layout.popupwindow, null); Button positiveBtn = (Button) view.findViewById(R.id.positiveBtn); positiveBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { LogUtil.i(LOG_TAG, "ok on click"); // 打开安装包 // 隐藏弹窗 WindowUtils.hidePopupWindow(); } }); Button negativeBtn = (Button) view.findViewById(R.id.negativeBtn); negativeBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { LogUtil.i(LOG_TAG, "cancel on click"); WindowUtils.hidePopupWindow(); } }); // 点击窗口外部区域可消除 // 这点的实现主要将悬浮窗设置为全屏大小,外层有个透明背景,中间一部分视为内容区域 // 所以点击内容区域外部视为点击悬浮窗外部 final View popupWindowView = view.findViewById(R.id.popup_window);// 非透明的内容区域 view.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { LogUtil.i(LOG_TAG, "onTouch"); int x = (int) event.getX(); int y = (int) event.getY(); Rect rect = new Rect(); popupWindowView.getGlobalVisibleRect(rect); if (!rect.contains(x, y)) { WindowUtils.hidePopupWindow(); } LogUtil.i(LOG_TAG, "onTouch : " + x + ", " + y + ", rect: " + rect); return false; } }); // 点击back键可消除 view.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: WindowUtils.hidePopupWindow(); return true; default: return false; } } }); return view; } }