需求描述
點擊“操作指導”按鈕,在其正下方彈出“產品說明書”、“操作視頻”兩個選項供用戶選擇,點擊PopupWindow外的任意位置關閉彈窗。
預期效果
預期效果.gif
需求實現及異常問題分析
-
需求實現
使用PopupWindow顯示內容,通過showAsDropDown(View anchor, int xoff, int yoff)方法顯示在指定按鈕的正下方,使用以下代碼配置來實現點擊PopupWindow內容區域外任意位置關閉彈窗功能:
ColorDrawable dw = new ColorDrawable(0x4c000000);// 新建一個ColorDrawable顏色為半透明
this.setBackgroundDrawable(dw);// 設置SelectPicPopupWindow彈出窗體的背景Drawable
this.setOutsideTouchable(true);// 設置PopupWindow內容區域外的區域是否響應點擊事件(true:響應;false:不響應)
問題來了!!!經過運行操作后發現,在點擊外部區域PopupWindow消失的同時,點擊區域下方如果剛好有View的話,還會響應它的點擊事件(這里是操作指導按鈕,導致該按鈕事件再次觸發彈出PopupWindow)!具體效果如下:
error.gif
-
異常問題分析
先來走趟Log吧...我分別在按鈕的點擊事件、PopupWindow的dismiss()方法中添加了如下Log:
// MainActivity
findViewById(R.id.main_btn_test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("MainActivity", "show popupWindow.");
popupWindow.showAsDropDown(view, (view.getWidth() - popupWindow.getWidth()) / 2, 0);
}
});
// PopupWindow
@Override
public void dismiss() {
super.dismiss();
Log.e("PopupWindow", "pop dismiss.");
}
發生上述異常問題時打印日志如下圖:
error_log.png
通過日志可以看出,因為我們點擊的位置下方剛好存在一個Button,在PopupWindow消失后,事件又進一步傳遞給了Button,從而觸發了Button的點擊事件導致了該問題的發生。
解決方法
那么我們該如何避免點擊PopupWindow外部區域彈窗消失后點擊事件再次向下傳遞呢(透傳給下方的View)?
其實這個方法大多數人都用過,只是很少有人記住——我們可以通過讓PopupWindow聚焦的方式,讓其它子控件獲取不到焦點,從而解決點擊事件透傳的問題,是的,只需要下面一行代碼即可:
this.setFocusable(true);// 聚焦點擊事件不會透傳給下面的View
同時,你會發現,把this.setOutsideTouchable(true);
這行代碼注釋掉同樣能達到預期效果,源碼上的邏輯分析。。。未完待續...
【拓展閱讀】
關于PopupWindow的避坑使用,推薦閱讀淺談PopupWindow在Android開發中的使用