最近在項(xiàng)目中用到了自定義Dialog,以前也是經(jīng)常用,只不過(guò)要么是用自帶的dialog樣式,要么也是很簡(jiǎn)單的布局,所以并沒(méi)有重視修改dialog大小的坑。直到這次項(xiàng)目中產(chǎn)(keng)品(die)經(jīng)(wan)理(yi)死了都說(shuō)dialog大小別扭要求改,然后突然發(fā)現(xiàn)自己自定義的dialog的大小不能調(diào)整后整個(gè)人都驚呆了,因此打算深入源碼看看解決這個(gè)問(wèn)題。本文分析的源代碼均來(lái)自Android API 24。
demo的自定義布局如下:

首先想著通過(guò)修改dialog的Window來(lái)進(jìn)行修改,代碼如下:


em.....emmmm???尼瑪?這啥玩意兒??還是沒(méi)變?再怎么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)建,這里面肯定大有文章,猜測(cè)是進(jìn)行了Dialog的創(chuàng)建,我們跟進(jìn)去查看具體源碼。

跟進(jìn)去后發(fā)現(xiàn)里面調(diào)用了onCreate()方法,在這里是不是有種似曾相識(shí)的感覺(jué)?怎么感覺(jué)和Activity差不多了呢?按捺住基動(dòng)的內(nèi)心我們跟進(jìn)去繼續(xù)看看。因?yàn)镈ialog的onCreate()方法實(shí)現(xiàn)為空的,所以我們選擇一個(gè)子類來(lái)進(jìn)行查看,我們進(jìn)入AlertDialog中查看:

我們發(fā)現(xiàn)調(diào)用了mAlet.installContent()方法,我們來(lái)看看這是什么東東。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()方法。是不是越來(lái)越熟悉這個(gè)套路!繼續(xù)忍著壓抑砰砰直跳的小內(nèi)心,繼續(xù)跟進(jìn)去看看。

我們看到,在Dialog類中我們發(fā)現(xiàn)它最終調(diào)用了Window的setContentView()方法;而Window在Android中只有PhoneWindow這一個(gè)實(shí)現(xiàn)類。 接下來(lái)的工作就是和Activity中的步驟一模一樣,因?yàn)槎际钦{(diào)用Window的setContentView()方法;具體分析可看我記錄的另一篇文章內(nèi)容(傳送門:http://www.itdecent.cn/p/28bbb6778593)。
通過(guò)setContentView()方法后,創(chuàng)建了Dialog的decorView,并且將我們的自定義布局加入到decorView中。其中在這個(gè)過(guò)程中,mWindowAttributes的高度和寬度在mWindow.setContentView()中的installDecor()中的generateLayout()中被修改,在這里貼出修改部分的代碼:



在上面圖中的標(biāo)注處調(diào)用了setLayout(int width,int height)方法,這里傳入了自適應(yīng)的常量方式。而在setLayout方法中首先獲取window的LayoutParams,然后修改了寬高。因此在這里過(guò)后,Window的mWindowAttributes將會(huì)重新改變,因此導(dǎo)致了我們?cè)趕how之前修改的mWindowAttributes值將被覆蓋,因此失效!
接下來(lái)把debug模式下錯(cuò)誤代碼的參數(shù)貼出來(lái)看看:


可以看出就算之前設(shè)置參數(shù),隨后在show方法中也會(huì)被覆蓋,因此在show之前設(shè)置參數(shù)無(wú)效。

至此我們就將設(shè)置Dialog的Window寬高沒(méi)有效果的原因分析完畢。