关于写这篇文章的目的是因为项目中要写一个PopupWindow的弹出框动画,结果碰到各种坑,各种百度,但是说的要么支离破碎,要么根本就是错的,所以再次整合了一下,并力所能及的解决了一些问题。
大部分人都碰到了PopupWindow点击外部不会消失或者点击没反应等等的情况,然而百度上解决的方法就那么几种可能你写完之后发现还是没什么用,其实并不是因为他们说错了,而是你创建pop时的设置和他们根本不同导致的问题,下面我详细的说明下各种创建方法会导致的问题已经解决方法。
其实大部分能不能关闭,能不能点击都是setFocusable是true还是false导致的,那么我将对这2种状态进行分析。
在mPopupWindow.setFocusable(true)时的情况
第一种情况:
new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
如果这里的高度是WRAP_CONTENT
(xml中的布局也到不满屏的地步)
第二种情况:
new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
如果这里的高度是MATCH_PARENT
在mPopupWindow.setFocusable(false)时的情况
第一种情况:
new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
1.1那么点击PopupWindow外部 PopupWindow并不会dismiss activity的onTouchEvent和dispatchTouchEvent也都能接受 总之PopupWindow以外的控件点击都是有效的
第二种情况:
new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
如果这里的高度是MATCH_PARENT
第二种解决方案:将showAsDropDown重写(调用自己重写的showAsDropDown, 将PopupWindow 当参数传进去
public void showAsDropDown(PopupWindow pw, View anchor, int xoff, int yoff) {
if (Build.VERSION.SDK_INT >= 24) {
Rect rect = new Rect();
anchor.getGlobalVisibleRect(rect);
int h = anchor.getResources().getDisplayMetrics().heightPixels - rect.bottom;
pw.setHeight(h);
pw.showAsDropDown(anchor, xoff, yoff);
} else {
pw.showAsDropDown(anchor, xoff, yoff);
}
}
还有一个问题 我
既想要点击外外部能让外部控件有反应 又要让内部的editView弹框呢(其实就是上面遗留的问题)
对pop内部的editView实现监听事件 使他强制弹框
popEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//强制弹出软键盘
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
});
然而这样还不够 键盘是弹出来了 可是被pop挡住了 需要在加上
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
但是还是有个问题 就是第一次点击editView并不会弹出键盘 第二次才会弹出(如果你activity的xml布局层级很深 可能需要点击很多次才会弹出 即使拿最外层的id去让它弹出 依然需要2次) 至于这个问题 我并没有什么好的方法可以解决 如果知道怎么解决的大佬请务必告诉我
利用pop的触摸监听来拦截
mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int height = v.getHeight();
float touchY = event.getY();
if (touchY > 0 && touchY < height) {
return false; //点击pop内部时 不进行拦截
}else {
MorePopOutSideTouchable(v, event); //自己写方法进行处理
return true; //点击pop外部是 进行拦截 不让事件传递下去
}
}
});
这里没什么特别好的方法 虽然解决了外部点击pop会消失 已经其他控件不响应的问题 但是在外部的区域 所有的控件 想要响应对应的点击事件
private void MorePopOutSideTouchable(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
}
最后我发现有些安卓的全面屏手机(系统在7.0以上)布局的需求是下方有阴影(参考某宝的 “我的”-->“账单”-->“筛选”或者“分类”的弹框)如果用setFocusable(fasle) 然后重写showAsDropDown使其弹框位置正确 也会出现最下方不会被阴影覆盖的情况(某宝暂时也没解决) 那么这个时候用setFocusable(true) 就可以解决了至于外部点击无效什么的 上面也说了解决方法。