全屏到任意寬高的Dialog的寫法

簡介

本篇博客主要是介紹如何實現全屏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設置全屏Dialog

總結:此類使用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設置全屏Dialog

總結:此方法通過設置themewindowIsFloating 爲false ,從而使得contentViewmatch_parentwindow起作用,從而達到全屏的效果,否則會設置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從而導致mIsFloatingtrue,然後通過代碼再次修改window的寬高即可達到修改的結果。

從上面那個比較長的代碼我們也可以看出,Dialog的寬高是可以自己設定的,所以通過此方法可以設定Dialog的任意寬高。

效果同效果圖2,在此不重複截圖了。

總結: 使用代碼設置寬高

  • 優點:粒度小,可以任意設置

  • 缺點:操作略微複雜


總結

至此你已經掌握了三種設置Dilaog全屏的方式和一種設置Dilaog任意寬高的方式,也知道了他們每個的優缺點,我將代碼上傳至 -> CSDN <- 中,寫了個簡單的工具,後續加入動畫的話,可以實現各種大小各種位置的Dialog的顯示,如有疑問,歡迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章