簡介
本篇博客主要是介紹如何實現全屏Dialog
,以及部分原理,具體細節可以參考對應Dialog
的源碼實現。
基礎知識
前提
講解前你需要具備如何去寫一個Dialog
的基礎知識,因爲本篇博客不會很細節的講解此處內容,此博客會着重講解如何實現一個全屏的Dialog
,當然有關此篇博客中探討出現的問題或者其他的疑問歡迎留言提問 ~。
實現方式
通過設置Style實現Dialog全屏
此方法比較簡單的就可以實現全屏的Dialog
,我們看下如何實現呢。
首先需要在res/values/styles.xml內寫入如下代碼即可:
<!--此處的名字可以任意寫,只要使用的時候匹配到即可-->
<style name="dialog_style_1">
<!--注意此處的屬性,設置此屬性後即可實現Dilaog全屏-->
<item name="android:windowFullscreen">true</item>
</style>
是不是很簡單,如上方聲明好一個Style
後,怎麼使用呢?
// 方式1,直接繼承Dialog的時候傳入Style即可
public class Dialog1 extends Dialog {
public Dialog1(@NonNull Context context) {
//注意此處
super(context, R.style.dialog_style_1);
setContentView(R.layout.dialog_test_layout);
}
}
//------------------
//方式2
Dialog dialog=new Dialog(context,R.style.dialog_style_1);
上面兩種實現的效果一致,是不是很簡單呢?
來個效果圖瞅瞅效果吧,效果圖如下:
總結:此類使用theme
的方式去設置全屏,設置windowFullscreen
屬性爲true 即可
- 優點:簡單,全屏
- 缺點:會導致整個屏幕被遮蓋,包括狀態欄,且點擊狀態欄會導致狀態欄再次顯示(體驗並不好),只適合全屏。
通過設置Style實現Dialog全屏2
看到上面的標題,你是不是懷疑我寫錯了,並沒有,這個也是通過Style實現的不過設置的屬性和上面的不同,達到的效果也不盡相同。
當然設置Style的方式和上面一樣只需要換個屬性就好了,按照如下設置:
<!--此屬性設置的dialog可以依照佈局的寬高去設定而不是wrap_content-->
<style name="dialog_style_2">
<!--注意此處-->
<item name="android:windowIsFloating">false</item>
</style>
當然使用方式也是一致的,按照如之前的使用方式,只需將R.style.dialog_style_1
更改爲R.style.dialog_style_2
即可。
看下效果圖:
總結:此方法通過設置theme
的windowIsFloating
爲false ,從而使得contentView
的match_parent
對window
起作用,從而達到全屏的效果,否則會設置window的寬高爲wrap_content
,無法全屏,當然你可以通過設置一個空的Style,也可達到相同效果(windowIsFloating
默認爲false),但不可以不設置Style,因爲會有默認的Style。
- 優點:簡單,顯示的window在狀態欄下面
- 缺點:粒度小,且window一直爲match_parent 即使內容變小,window仍不變小 ,導致外部無法觸發點擊消失事件,適合顯示在狀態欄下全屏的dialog,只適合全屏
通過代碼設置Dilaog全屏或者任意寬高
這個方法內就比較靈活了,你可以任意設置Dilaog的寬高,不過代碼量也會變高,好吧,看下怎麼實現。
上代碼:
public class Dialog3 extends Dialog {
public Dialog3(@NonNull Context context, float widthPercent, float heightPercent) {
super(context);
setContentView(R.layout.dialog_test_layout);
// 注意此方法一定要在setContentView後面,否則設置內容會被setContentView覆蓋,此時由於默認沒使用theme,按照默認的背景圖來設置
// 此時再設置window的寬高進行更細緻的修改window參數
initWidthAndHeightByPercent(widthPercent, heightPercent);
}
/**
* 用於根據傳入的寬高的比例顯示window
*/
private void initWidthAndHeightByPercent(float widthPercent, float heightPercent) {
WindowManager windowManager = getWindow().getWindowManager();
Display display = windowManager.getDefaultDisplay();
WindowManager.LayoutParams lp = getWindow().getAttributes();
//decorView是window中的最頂層view,可以從window中獲取到decorView,獲取狀態欄的高度
int statusBarHeight = getStatusBarHeight();
lp.width = (int) (display.getWidth() * widthPercent); //設置寬度
//高度值需要減去狀態欄的高度
lp.height = (int) ((display.getHeight() - statusBarHeight) * heightPercent);
getWindow().setAttributes(lp);
// 注意此處必須設置,因爲window默認會設置一個有padding 的背景
getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
}
private int getStatusBarHeight() {
int statusBarHeight1 = -1;
//獲取status_bar_height資源的ID
int resourceId = getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
//根據資源ID獲取響應的尺寸值
statusBarHeight1 = getContext().getResources().getDimensionPixelSize(resourceId);
}
return statusBarHeight1;
}
}
不要被上面的代碼嚇壞了,其實內容也不多,我來講解下主要過程,首先需要注意的就是你設置window
的寬高的代碼一定要在setContentView
之後,原因和方法2中提到的相關,其內部會將不設置android:windowIsFloating
屬性的window
按照wrap_content
來測量,所以,即使你設置match_parent
也是無效的,而我們如果通過代碼手動修改寬高當然也就達到修改的目的,如果順序修改,就會導致setContentView
方法將其重置。
具體參考PhoneWindow
的代碼(節選):
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
}
這個代碼就是在setContentView
內執行,很明顯,由於你沒設置Style
,系統將會使用默認的Style
從而導致mIsFloating
爲true
,然後通過代碼再次修改window
的寬高即可達到修改的結果。
從上面那個比較長的代碼我們也可以看出,Dialog
的寬高是可以自己設定的,所以通過此方法可以設定Dialog
的任意寬高。
效果同效果圖2,在此不重複截圖了。
總結: 使用代碼設置寬高
優點:粒度小,可以任意設置
缺點:操作略微複雜
總結
至此你已經掌握了三種設置Dilaog
全屏的方式和一種設置Dilaog
任意寬高的方式,也知道了他們每個的優缺點,我將代碼上傳至 -> CSDN <- 中,寫了個簡單的工具,後續加入動畫的話,可以實現各種大小各種位置的Dialog的顯示,如有疑問,歡迎留言。