PopupWindow返回键和点击外部无法消失
2017-04-12 16:44
399 查看
今天查看项目代码,看到这个PopupWindow 让我想起了当初碰到的一个坑:PopupWindow 点击外部和返回键无法消失。现在闲暇记录一下:为PopupWindow 设置一个背景
popupWindow.setBackgroundDrawable(drawable);
就这么简单 -_-
从源码上分析一下:
先看看弹出框显示的时候代码showAsDropDown,里面有个preparePopup方法
再看preparePopup方法
上面可以看到mBackground不为空的时候,会PopupViewContainer作为mContentView的Parent,下面看看PopupViewContainer到底干了什么
看到上面红色部分的标注可以看出,这个内部类里面封装了处理返回键退出和点击外部退出的逻辑,但是这个类对象的构造过程中(preparePopup方法中)却有个mBackground != null的条件才会创建
而mBackground对象在setBackgroundDrawable方法中被赋值,看到这里应该就明白一切了。
popupWindow.setBackgroundDrawable(drawable);
就这么简单 -_-
从源码上分析一下:
先看看弹出框显示的时候代码showAsDropDown,里面有个preparePopup方法
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { if (isShowing() || mContentView == null) { return; } registerForScrollChanged(anchor, xoff, yoff, gravity); mIsShowing = true; mIsDropdown = true; WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken()); preparePopup(p); updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity)); if (mHeightMode < 0) p.height = mLastHeight = mHeightMode; if (mWidthMode < 0) p.width = mLastWidth = mWidthMode; p.windowAnimations = computeAnimationResource(); invokePopup(p); }
再看preparePopup方法
/** * <p>Prepare the popup by embedding in into a new ViewGroup if the * background drawable is not null. If embedding is required, the layout * parameters' height is modified to take into account the background's * padding.</p> * * @param p the layout parameters of the popup's content view */ private void preparePopup(WindowManager.LayoutParams p) { if (mContentView == null || mContext == null || mWindowManager == null) { throw new IllegalStateException("You must specify a valid content view by " + "calling setContentView() before attempting to show the popup."); } if (mBackground != null) { final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams(); int height = ViewGroup.LayoutParams.MATCH_PARENT; if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) { height = ViewGroup.LayoutParams.WRAP_CONTENT; } // when a background is available, we embed the content view // within another view that owns the background drawable PopupViewContainer popupViewContainer = new PopupViewContainer(m 4000 Context); PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, height ); popupViewContainer.setBackground(mBackground); popupViewContainer.addView(mContentView, listParams); mPopupView = popupViewContainer; } else { mPopupView = mContentView; } mPopupView.setElevation(mElevation); mPopupViewInitialLayoutDirectionInherited = (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT); mPopupWidth = p.width; mPopupHeight = p.height; }
上面可以看到mBackground不为空的时候,会PopupViewContainer作为mContentView的Parent,下面看看PopupViewContainer到底干了什么
private class PopupViewContainer extends FrameLayout { private static final String TAG = "PopupWindow.PopupViewContainer"; public PopupViewContainer(Context context) { super(context); } @Override protected int[] onCreateDrawableState(int extraSpace) { if (mAboveAnchor) { // 1 more needed for the above anchor state final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET); return drawableState; } else { return super.onCreateDrawableState(extraSpace); } } @Override public boolean dispatchKeyEvent(KeyEvent event) { // 这个方法里面实现了返回键处理逻辑,会调用dismiss if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (getKeyDispatcherState() == null) { return super.dispatchKeyEvent(event); } if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { KeyEvent.DispatcherState state = getKeyDispatcherState(); if (state != null) { state.startTracking(event, this); } return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { KeyEvent.DispatcherState state = getKeyDispatcherState(); if (state != null && state.isTracking(event) && !event.isCanceled()) { dismiss(); return true; } } return super.dispatchKeyEvent(event); } else { return super.dispatchKeyEvent(event); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) { return true; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { // 这个方法里面实现点击消失逻辑 final int x = (int) event.getX(); final int y = (int) event.getY(); if ((event.getAction() == MotionEvent.ACTION_DOWN) && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) { dismiss(); return true; } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { dismiss(); return true; } else { return super.onTouchEvent(event); } } @Override public void sendAccessibilityEvent(int eventType) { // clinets are interested in the content not the container, make it event source if (mContentView != null) { mContentView.sendAccessibilityEvent(eventType); } else { super.sendAccessibilityEvent(eventType); } } }
看到上面红色部分的标注可以看出,这个内部类里面封装了处理返回键退出和点击外部退出的逻辑,但是这个类对象的构造过程中(preparePopup方法中)却有个mBackground != null的条件才会创建
而mBackground对象在setBackgroundDrawable方法中被赋值,看到这里应该就明白一切了。
相关文章推荐
- android PopupWindow点击外部和返回键消失的解决方法
- popupwindow的基本应用,点击外部消失
- 点击PopupWindow外部消失
- PopupWindow点击外部区域不能消失的解决办法
- PopupWindow如何在外部点击消失和返回键
- PopupWindow(弹窗)点击空白区域和返回键消失
- [Android]PopupWindow 点击外部区域无法关闭的问题
- Android中popupWindow点击外面区域以及返回键,使popupWindow消失的方法
- Dialog弹出的时候,禁止点击外部消失和禁用返回键
- PopupWindow点击外部区域消失(二)
- 从源码剖析PopupWindow 兼容Android 6.0以上版本点击外部不消失
- 关于popupWindow点击屏幕其他地方或返回键消失
- PopupWindow点击外部和返回键消失遇到的坑
- ProgressDialog 点击外部 弹窗不消失,点击back键可以返回
- PopupWindow在点击外部区域的时候消失(二)
- PopupWindow点击外部区域消失
- Android中PopupWindow点击窗口之外和返回键消失,界面锁定的实现。
- Android PopupWindow点击返回键与pop外消失
- Android中PopupWindow点击窗口之外和返回键消失,界面锁定的实现
- android PopupWindow点击外部和返回键消失