最近有个需求,需要自定义一个通用的popupwindow以供各个项目调用,其中有个需求是,该popupwindow需要能够灵活的控制其点击空白处是否隐藏。
关于这个问题,网上流传最广的解决方式是
PopupWindow mPopupWindow = new PopupWindow();
// 设置popupWindow,当点击popupWindow外面的时候可以消失
mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
mPopupWindow.setOutsideTouchable(true);
// 设置监听
mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE && !mPopupWindow.isFocusable()) {
// 如果焦点不在popupWindow上,且点击了外面,不再往下dispatch事件:
// 不做任何响应,不 dismiss popupWindow
return true;
}
// 否则default,往下dispatch事件:关掉popupWindow,
return false;
}
});
但是我发现根本就捕捉不到ACTION_OUTSIDE这个状态,也就是说
if (event.getAction() == MotionEvent.ACTION_OUTSIDE && !mPopupWindow.isFocusable()) {
// 如果焦点不在popupWindow上,且点击了外面,不再往下dispatch事件:
// 不做任何响应,不 dismiss popupWindow
return true;
}
这段代码根本就进不去,我的API版本是Android4.0.3。有兴趣的人可以测试一下其它几个版本的API。
经过测试发现,其实只要你为popupwindow设置了背景,那么点击它之外的空白区域就会默认将该popupwindow给隐藏,如果不为它设置背景,那么就不会隐藏。于是我们的解决方法来了。
方法一:
public void setIsDismissTouchOutside(boolean isDismiss) {
if(isDismiss){
ColorDrawable dw = new ColorDrawable(0);
setBackgroundDrawable(dw);
}
}
通过是否为popupwindow设置背景来设置点击空白处是否隐藏。
但是在某些情况,可能我们已经为popupwindow设置了背景,但是又希望能够实现该需求,此时我们该如何解决呢。我们可以参考一下最开始的那段代码,通过捕捉popupwindow的触摸事件来判断是否触摸了popupwindow的外部来实现需求。由于我们无法捕捉到ACTION_OUTSIDE这个状态,所以我们需要通过手动判断来是否触摸了外部
我们来看一张图
当我们通过popupwindow的setTouchInterceptor()方法来获取触摸点坐标时,该坐标是以popupwindow的左上角为原点,向右为X正轴,向下为Y正轴的坐标系的坐标。那么我们的解决办法来了
public void setIsDismissTouchOutside(boolean isDismiss) {
if (isDismiss) {
setTouchInterceptor(null);
return;
}
// 设置监听
setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
// 获取popupwindow的宽度
float maxX = getMeasuredWidth();
// 获取popupwindow的高度
float maxY = getMeasureHeight();
// 判断触摸点是否在popwindow范围内,如果不在范围内,消费该点击事件
if (x <= 0 || y <= 0 || x >= maxX || y >= maxY) {
return true;
}
// 否则default,往下dispatch事件
return false;
}
});
}
/**
* 测量高度
*
* @return
*/
private int getMeasureHeight() {
getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int popHeight = getContentView().getMeasuredHeight();
return popHeight;
}
/**
* 测量宽度
*
* @return
*/
private int getMeasuredWidth() {
getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int popWidth = getContentView().getMeasuredWidth();
return popWidth;
}
以上代码在Android4.0.3测试通过。
如有错漏之处,欢迎指出,感激不尽