touch here
android在WindowManager添加View
作者:feiyangxiaomi
项目的驱动,希望提供一个弹窗,这个弹窗的特点是:
- 非阻塞试弹窗,弹窗弹出的时候,点击弹窗外的屏幕区域,–不选PopupWindow(开源项目QuickAction不能用)
- 弹窗需要内部能够点击某一项并做出相应,–不选Toast
此时考虑在界面上加入一个View,通过WindowManager.addView方法去添加弹出图层,这里先贴出一个图,看一下这个效果是否是你的菜:
//截图
WindowManager用来在应用与window之间的管理接口,管理窗口顺序,消息等。对于windowManager来说一个系统只有一个,它是由系统底层实现的,用于负责调度当前显示那个窗口,消息处理我们获得一个windowManager的方式如下:
WindowManager windowManager = (WindowManager)context().getSystemService(Context.WINDOW_SERVICE);
调用比较简单。
把这个弹窗叫做PopupAction
,后面统一为这个称呼。
PopupAction
代码 /**
* Show quick menu popup. Popup is automatically positioned, on top of anchor view. Calc of anchor and mRootView
* view for look out the poosition. Every side margin of 10dp and the arrow at the top of anchor.
*
* @param context the global information about an applicaion environment
* @param anchor view of call for
* @param actions action list items {@link #addActionItem(List)}
*/
public void show(Context context, View anchor, List actions) {
mContext = context;
if (mContext == null) {
Log.i("MenuDialog", "context is null");
return;
}
int xPos;
int yPos;
int arrowPos;
int[] location = new int[2];
//添加菜单项
addActionItem(actions);
mShowAction = true;
//计算要弹出的位置
anchor.getLocationOnScreen(location);
Rect anchorRect =
new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1] + anchor.getHeight());
int rootHeight = mRootView.getMeasuredHeight();
int rootWidth = mRootView.getMeasuredWidth();
xPos = anchorRect.centerX() - (rootWidth / 2);
//对弹窗靠近左边和右边的处理
if (xPos < 20) {
xPos = 20;
}
DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
if ((dm.widthPixels - anchorRect.centerX()) < rootWidth / 2) {
xPos = dm.widthPixels - rootWidth - 20;
}
arrowPos = anchorRect.centerX() - xPos;
yPos = anchorRect.top - rootHeight;
//设置箭头位置
showArrow((R.id.arrow_down), arrowPos);
//添加图层弹窗
android.view.WindowManager.LayoutParams params =
(android.view.WindowManager.LayoutParams) mRootView.getLayoutParams();
params.x = xPos;
params.y = yPos;
mWM.addView(mParentView, params);
mParentView.addView(mRootView);
mParentView.setOnTouchListener(this);
//设置弹出动画
Animation animationUp = AnimationUtils.loadAnimation(mContext, R.anim.grow_from_bottom);
mRootView.startAnimation(animationUp);
}
其中初始化View,添加菜单项和设置点击菜单项的点击回调,参考QuickAction的代码,这里不再介绍。
mParams = new WindowManager.LayoutParams();
mParams.height = LayoutParams.WRAP_CONTENT;
mParams.width = LayoutParams.WRAP_CONTENT;
mParams.format = PixelFormat.TRANSLUCENT;
mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
mParams.flags =
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mParams.gravity = Gravity.TOP | Gravity.LEFT;
mRootView.setLayoutParams(mParams);
可以看到这里使用的type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
,后面介绍一下几种类型。
flag使用
- LayoutParams.FLAG_NOT_TOUCH_MODAL
表示可以点击弹窗之外的屏幕区域,这是必须的。
- LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
表示可以监听外部点击事件,这时候可以dismiss掉当前的弹窗,也是必需的。
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
表示当前弹窗捕获得焦点,但能点击,非常重要。不然键盘区域的所有touch事件都会收不到。
Constants | |
---|---|
TYPE_ACCESSIBILITY_OVERLAY | 窗口重叠仅由AccessibilityService截取用户交互,而不改变窗口的无障碍服务可以内省。 |
TYPE_APPLICATION | 应用窗口 |
TYPE_APPLICATION_ATTACHED_DIALOG | 和TYPE_APPLICATION_PANEL类似,但是不作为一个应用的一部分,显示在窗口的顶层 |
TYPE_APPLICATION_PANEL | 应用顶层图层 |
TYPE_APPLICATION_MEDIA | 播放器图层 |
TYPE_APPLICATION_STARTING | 应用开始事的图层 |
TYPE_APPLICATION_SUB_PANEL | 应用子面板 |
TYPE_PHONE | 电话图层,部分手机无法使用,已测试 |
~ | |
TYPE_SYSTEM_ALERT | 系统通知,使用时发现该图层会独立在应用之上 |
TYPE_SYSTEM_DIALOG | 系统对话框,使用时发现该图层会独立在应用之上 |
TYPE_SYSTEM_ERROR | 系统错误,非常靠上 |
TYPE_SYSTEM_OVERLAY | 系统普通图层 |
TYPE_TOAST | 系统toast |
参考网上实例的时候,建议不要采用系统图层,网上的好多实例都是采用:TYPE_SYSTEM_ALERT
,不合理。
动画部分可以采用:
WindowManager.windowAnimations=R.style.xxx
但是不建议使用,该资源在官网上说是鼻息使用系统资源,因为window manager拿到应用的资源。
那怎么办?参考:WindowManager with Animation (is it possible?)
代码如下所示:
mParentView = new FrameLayout(mContext);
mWM.addView(mParentView, params);
mParentView.addView(mRootView);
Animation animationUp = AnimationUtils.loadAnimation(mContext, R.anim.grow_from_bottom);
mRootView.startAnimation(animationUp);
借助于ViewGroup(定义的mParentView),使用动画效果,小技巧很不错。