之前沒(méi)有區(qū)別過(guò) focusable 和 touchable 的關(guān)系拓提,使用 PopupWindow 時(shí)臼闻,發(fā)現(xiàn)對(duì)窗口外的事件響應(yīng)理解不清晰跪帝。
理解 focusable 和 touchable
touchable 就不用多言了,focusable 的作用則需要明確一下些阅。
focus 其實(shí)主要是給“硬件輸入”用的伞剑,比如以前的鍵盤(pán)手機(jī),使用上下左右鍵移動(dòng)時(shí)市埋,被選擇的部分就會(huì)高亮:
如果 View focusable 屬性是 false黎泣,使用鍵盤(pán)(實(shí)體鍵盤(pán))時(shí)就無(wú)法選擇這個(gè) View∷×酰現(xiàn)在手機(jī)很少使用鍵盤(pán)了,但 focusable 依然與日常開(kāi)發(fā)有關(guān)系:not focusable 的 View 不能獲取焦點(diǎn)抒倚,無(wú)法使用鍵盤(pán)(包括實(shí)體鍵盤(pán)和軟鍵盤(pán))輸入內(nèi)容褐着。所以,如果把 EditText 設(shè)置 focusable 為 false托呕,就會(huì)發(fā)現(xiàn) EditText 無(wú)法輸入文字含蓉。
這樣分析下來(lái),touchable 和 focusable 好像沒(méi)什么關(guān)系项郊。這兩個(gè)本質(zhì)確實(shí)沒(méi)什么關(guān)系馅扣,但點(diǎn)擊 EditText 時(shí),EditText 能輸入了着降,說(shuō)明 EditText 在被點(diǎn)擊時(shí)順帶請(qǐng)求獲取了焦點(diǎn)(focusable 為 true)差油。
WindowManager.LayoutParams 的 focusable,touchable
FLAG_NOT_FOCUSABLE:
整個(gè)窗口都無(wú)法獲取焦點(diǎn)任洞,收到的操作(key or other button events)蓄喇,也不能使用鍵盤(pán)打字。焦點(diǎn)的事件都被下層窗口接收交掏。同時(shí)妆偏,自動(dòng)設(shè)置?FLAG_NOT_TOUCH_MODAL 標(biāo)志。
FLAG_NOT_TOUCHABLE:字面意思盅弛,無(wú)法獲取觸摸輸入事件
FLAG_NOT_TOUCH_MODAL:即使?focusable楼眷,也把窗口外的事件傳遞給下層窗口
(這個(gè)即使需要好好理解。not focusable 時(shí)熊尉,默認(rèn)就把窗口外的時(shí)間傳遞給下層窗口了,而 focusable? 且 touchable 時(shí)掌腰,窗口內(nèi)外的事件都會(huì)被當(dāng)前窗口處理狰住。所以,當(dāng)希望窗口 focusable齿梁,窗口內(nèi)事件當(dāng)前窗口處理催植,窗口外事件其他窗口處理時(shí),就需要使用這個(gè)標(biāo)志位)勺择。
FLAG_WATCH_OUTSIDE_TOUCH:只有在設(shè)置了?FLAG_NOT_TOUCH_MODAL 標(biāo)志后创南,該標(biāo)志位才有效。窗口外事件發(fā)送給下層窗口省核,但本層窗口會(huì)收到一個(gè) ACTION_CANCEL稿辙。
FLAG_LOCAL_FOCUS_MODE:用不上,先忽略
FLAG_ALT_FOCUSABLE_IM:對(duì)于輸入法气忠,將?FLAG_NOT_FOCUSABLE 的效果取反邻储。
兩種情況:
1. 設(shè)置?FLAG_NOT_FOCUSABLE 時(shí)赋咽,窗口本來(lái)應(yīng)該無(wú)法輸入內(nèi)容,且位置和布局不隨鍵盤(pán)變化(FLAG_SOFT_ADJUST_* 相關(guān)標(biāo)記位完全失效)吨娜。設(shè)置?FLAG_NOT_FOCUSABLE 后脓匿,位置和布局不隨鍵盤(pán)變化(但依然無(wú)法輸入內(nèi)容,底層窗口可以響應(yīng)事件)宦赠。
2. 沒(méi)有設(shè)置?FLAG_NOT_FOCUSABLE 時(shí)陪毡,本來(lái)應(yīng)該是能夠輸入內(nèi)容,且位置和布局不隨鍵盤(pán)變化(具體變化規(guī)則由 FLAG_SOFT_ADJUST_* 標(biāo)志確定)勾扭。設(shè)置?FLAG_NOT_FOCUSABLE 后毡琉,位置和布局不隨鍵盤(pán)變化,且無(wú)法用鍵盤(pán)輸入內(nèi)容尺借。
PopupWindow 的 focusable绊起,touchable
有了 WindowManager.LayoutParams 基礎(chǔ),就可以分析 PopupWindow 的 focusable燎斩,touchable 了虱歪。
PopupWindow 通過(guò)?setFocusable,setTouchable栅表,setTouchModal笋鄙,setOutsideTouchable 來(lái)關(guān)聯(lián) WindowManager.LayoutParams 的相關(guān)標(biāo)記位。
要注意的是怪瓶,mNotTouchModal 是 private的萧落,并且 setTouchModal 是 @hide 的,所以 mNotTouchModal 由 PopupWindow 內(nèi)部設(shè)置洗贰,應(yīng)用開(kāi)發(fā)中無(wú)法更改 mNotTouchModal找岖。
看 PopupWindow 的?createPopupLayoutParams 方法(使用了 computeFlags 方法)就能知道 PopupWindow 的標(biāo)記位和 WindowManager.LayoutParams 之間的對(duì)應(yīng)關(guān)系:
看文檔中對(duì)?setOutsideTouchable 的描述,為什么只有在 touchable 但 not focusable 狀態(tài)時(shí)能夠生效呢敛滋?
從 computeFlags 方法中可以看到许布,mOutsideTouchable 對(duì)應(yīng)的就是 FLAG_WATCH_OUTSIDE_TOUCH,前面說(shuō)到绎晃,F(xiàn)LAG_WATCH_OUTSIDE_TOUCH 依賴于 FLAG_NOT_TOUCH_MODAL蜜唾,而 FLAG_NOT_TOUCH_MODAL 又只有在設(shè)置 FLAG_NOT_FOCUSABLE 情況下才算生效,也就對(duì)應(yīng)于 PopupWindow 的 setFocusable(false)庶艾。
Dialog 的 focusable袁余,touchable?
Dialog 內(nèi)部使用 PhoneWindow 創(chuàng)建窗口咱揍,所以可以直接獲取 Window颖榜,修改屬性。