最近在項(xiàng)目中用到了自定義Dialog颅眶,以前也是經(jīng)常用寥院,只不過要么是用自帶的dialog樣式掰盘,要么也是很簡單的布局欠橘,所以并沒有重視修改dialog大小的坑矩肩。直到這次項(xiàng)目中產(chǎn)(keng)品(die)經(jīng)(wan)理(yi)死了都說dialog大小別扭要求改,然后突然發(fā)現(xiàn)自己自定義的dialog的大小不能調(diào)整后整個(gè)人都驚呆了肃续,因此打算深入源碼看看解決這個(gè)問題黍檩。本文分析的源代碼均來自Android API 24。
demo的自定義布局如下:
首先想著通過修改dialog的Window來進(jìn)行修改痹升,代碼如下:
em.....emmmm???尼瑪建炫?這啥玩意兒?疼蛾?還是沒變?再怎么4000的大小也不會(huì)是這么個(gè)小玩意兒把艺配?郁悶之極....(我太仁慈大小給4000太小了察郁?)
然而百思不得其解為什么必須要在show之后才能顯示末荐??按照正常邏輯不應(yīng)該在show之前設(shè)置大行滦狻甲脏??妹笆?
show方法中的代碼居然不是我想象中的一兩行代碼,而是那么多窟坐!首先在上圖中標(biāo)注1處,因?yàn)槲覀兪莿?chuàng)建新的dialog,所以會(huì)執(zhí)行dispatchOnCreate(null)這個(gè)方法海渊。顧名思義,調(diào)用創(chuàng)建狸涌,這里面肯定大有文章切省,猜測是進(jìn)行了Dialog的創(chuàng)建,我們跟進(jìn)去查看具體源碼帕胆。
跟進(jìn)去后發(fā)現(xiàn)里面調(diào)用了onCreate()方法朝捆,在這里是不是有種似曾相識的感覺?怎么感覺和Activity差不多了呢懒豹?按捺住基動(dòng)的內(nèi)心我們跟進(jìn)去繼續(xù)看看芙盘。因?yàn)镈ialog的onCreate()方法實(shí)現(xiàn)為空的,所以我們選擇一個(gè)子類來進(jìn)行查看脸秽,我們進(jìn)入AlertDialog中查看:
我們發(fā)現(xiàn)調(diào)用了mAlet.installContent()方法儒老,我們來看看這是什么東東。AlertController是一個(gè)AlertDialog的控制類记餐,包括在創(chuàng)建AlertDialog時(shí)(代碼如下):
AlertDialog mTextDialog = new AlertDialog.Builder(context).setTitle("溫馨提示").setView(view) .create();
在這里使用的Builder模式中驮樊,setTitle之類的設(shè)置參數(shù)也是先將參數(shù)設(shè)置給AlertController.Param。具體在這里就暫時(shí)不管。
我們繼續(xù)查看installContent()方法:
先設(shè)置dialog的contentView,然后調(diào)用setContentView()方法囚衔。是不是越來越熟悉這個(gè)套路挖腰!繼續(xù)忍著壓抑砰砰直跳的小內(nèi)心,繼續(xù)跟進(jìn)去看看练湿。
我們看到猴仑,在Dialog類中我們發(fā)現(xiàn)它最終調(diào)用了Window的setContentView()方法;而Window在Android中只有PhoneWindow這一個(gè)實(shí)現(xiàn)類。 接下來的工作就是和Activity中的步驟一模一樣肥哎,因?yàn)槎际钦{(diào)用Window的setContentView()方法辽俗;具體分析可看我記錄的另一篇文章內(nèi)容(傳送門:http://www.reibang.com/p/28bbb6778593)。
通過setContentView()方法后篡诽,創(chuàng)建了Dialog的decorView,并且將我們的自定義布局加入到decorView中崖飘。其中在這個(gè)過程中,mWindowAttributes的高度和寬度在mWindow.setContentView()中的installDecor()中的generateLayout()中被修改霞捡,在這里貼出修改部分的代碼:
在上面圖中的標(biāo)注處調(diào)用了setLayout(int width,int height)方法坐漏,這里傳入了自適應(yīng)的常量方式。而在setLayout方法中首先獲取window的LayoutParams,然后修改了寬高碧信。因此在這里過后赊琳,Window的mWindowAttributes將會(huì)重新改變,因此導(dǎo)致了我們在show之前修改的mWindowAttributes值將被覆蓋砰碴,因此失效躏筏!
接下來把debug模式下錯(cuò)誤代碼的參數(shù)貼出來看看:
可以看出就算之前設(shè)置參數(shù)呈枉,隨后在show方法中也會(huì)被覆蓋趁尼,因此在show之前設(shè)置參數(shù)無效。
至此我們就將設(shè)置Dialog的Window寬高沒有效果的原因分析完畢。