setOutsideTouchable
setOutsideTouchable(true),點(diǎn)擊非PopupWindow視圖區(qū)域,直接隱藏PopupWindow。調(diào)用setOutsideTouchable(true)會(huì)使得點(diǎn)擊非PopupWindow視圖區(qū)域,PopupWindow能夠接收到ACTION_OUTSIDE事件,接收到這個(gè)事件后執(zhí)行dismiss。但是在5.0以下需要調(diào)用setBackground給PopupWindow設(shè)置一個(gè)非空的背景才會(huì)起作用。
小于5.0分析
5.0以下的PopupWindow,當(dāng)mBackground為非null時(shí),才會(huì)創(chuàng)建PopupViewContainer來(lái)封裝contentView,而ACTION_OUTSIDE的處理正是由其來(lái)處理。點(diǎn)擊查看4.4源代碼
private void preparePopup(WindowManager.LayoutParams p) {
......
if (mBackground != null) {
......
PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
......
mPopupView = popupViewContainer;
} else {
mPopupView = mContentView;
}
......
}
private class PopupViewContainer extends FrameLayout {
......
@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);
}
}
......
}
大于等于5.0分析
和小于5.0分析類似,大于等于5.0的PopupWindow,不管mBackground是否為null,都會(huì)創(chuàng)建PopupDecorView來(lái)封裝contentView。PopupDecorView會(huì)處理ACTION_OUTSIDE事件。點(diǎn)擊查看5.0源代碼
......
private void preparePopup(WindowManager.LayoutParams p) {
......
// When a background is available, we embed the content view within
// another view that owns the background drawable.
if (mBackground != null) {
mBackgroundView = createBackgroundView(mContentView);
mBackgroundView.setBackground(mBackground);
} else {
mBackgroundView = mContentView;
}
mDecorView = createDecorView(mBackgroundView);
......
}
......
private PopupDecorView createDecorView(View contentView) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
final int height;
if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
height = WRAP_CONTENT;
} else {
height = MATCH_PARENT;
}
final PopupDecorView decorView = new PopupDecorView(mContext);
decorView.addView(contentView, MATCH_PARENT, height);
decorView.setClipChildren(false);
decorView.setClipToPadding(false);
return decorView;
}
......
private class PopupDecorView extends FrameLayout {
......
@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);
}
}
......
}
setFocusable
調(diào)用setFocusable(true),按back鍵先隱藏PopupWindow而不是整個(gè)Activity。setFoucusable(true)將PopupWindow的mFoucusable設(shè)置為true。在PopupWindow顯示時(shí)如果mFoucusable為false,則會(huì)將FLAG_NOT_FOCUSABLE設(shè)置到Window上,導(dǎo)致系統(tǒng)按鍵事件不會(huì)派發(fā)給PopupWindow。mFoucusable默認(rèn)為false,所以這就是必須調(diào)用setFocusable(true)的原因。