Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android編程之DialogFragment源碼詳解(一)

Android編程之DialogFragment源碼詳解(一)

編輯:關於Android編程

DialogFragment是Fragment家族成員之一,如果你把它簡單的理解成Dialog,那就錯了。它的確可以做作dialog顯示,還可以顯示出自己定義的Dialog或者AlertDialog,但它同時也是一個Fragment。

按照官方的話來理解就是,你既可以把它當成一個dialog顯示出來,也可以讓它作為一個Fragment嵌套在Activity中,這樣更方便開發。

為什麼這麼說呢?試想一下,當產品需求最開始把它作為一個界面顯示的時候,你可能已經把它作為Fragment已經寫好了,但中途產品又把它設計成一個dialog,那你該怎麼辦?重新去一個dialog或者activity嗎?以前的傳參怎麼辦?過兩天,產品又將它改回去,你還要再重寫一遍嗎?等等一系列的問題就來了。

所以,這個時候,你只需要把當前的Fragment繼承類改為DialogFragment,再添加幾行代碼就可以了。其他的,基本都不用動。即使過兩天再改回來,或者別的界面也需要它的時候,你就可以直接把它當做Fragment,繼續使用,代碼都不用改。

這一點,不得不贊一下Fragment這個的出現,大大方便了開發,再也不怕產品設計調整界面布局了!


這裡多啰嗦一句,如果產品已經定義好了作為dialog,或者之前就是dialog的,就不要將它們改成DialogFragment的了,還是那句話:只做有意義的代碼改動!


DialogFragment的使用用例,官方文檔已經寫得很清楚了,Demo例子也有,在androidSDK的sample文件夾中,有需要的請自行查閱。

今天之所以翻出源碼來,主要還是希望通過對代碼的了解,更好使用DialogFragment。而且有些細節部分,不看源碼的話,可能就真在方法傳值時傳錯了。比如:style的設置!

在源碼最開始部分,就定義了style的常量:

    public static final int STYLE_NORMAL = 0;
    public static final int STYLE_NO_TITLE = 1;
    public static final int STYLE_NO_FRAME = 2;
    public static final int STYLE_NO_INPUT = 3;

STYLE_NORMAL:會顯示一個普通的dialog

STYLE_NO_TITLE:不帶標題的dialog

STYLE_NO_FRAME:無框的dialog

STYLE_NO_INPUT:無法輸入內容的dialog,即不接收輸入的焦點,而且觸摸無效。

說起來,android很多參數的設置,都有用到“|”的方法,表示支持兩種或兩種以上。最常見的,就是“Top|Left”,所以,在這裡有很多人會想用吧:STYLE_NO_TITLE|STYLE_NO_INPUT。那你可就錯了,這麼用的結果就是把style設置成了:STYLE_NO_INPUT ( 因為:1 | 3 = 3 )


接下來,再看一下它的內部變量:

    int mStyle = STYLE_NORMAL;
    int mTheme = 0;
    boolean mCancelable = true;
    boolean mShowsDialog = true;
    int mBackStackId = -1;

    Dialog mDialog;
    boolean mViewDestroyed;
    boolean mDismissed;
    boolean mShownByMe;

mStyle:默認的樣式為STYLE_NORMAL;

mTheme:主題,默認沒有設置,而是在setStyle(int style, int theme) 方法中,對其初始化設置,下面會講到;

mCancelable:是否可以取消,默認是ture,實際上就是設置給Dialog的mDialog.setCancelable(mCancelable);

mShowsDialog:這個參數我放到下面去講,默認也為true

mBackStackId:後退棧的ID,也就是說,當DialogFragment不顯示時,會清空棧裡的數據。(關於後退棧的問題,請留心我後面關於FragmentManager詳解的文章);

mDialog:DialogFragment之所以會以窗口方式顯示,實際上就是其內部有一個Dialog,也就是它,上面的樣式、主題、可取消都是設置給它的;

後面三個boolean的變量,就是標志位:

mViewDestroyed:標志位,在Dialog不顯示時,處理Fragment的移除操作;

mDismissed:標志位,Dialog是否不顯示了;

mShownByMe:標志位,在Dialog是否顯示,和mDismissed基本是一對;


DialogFragment的構造方法是空的,什麼也沒有:

    public DialogFragment() {
    }

然後就是setStyle方法:

    public void setStyle(int style, int theme) {
        mStyle = style;
        if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) {
            mTheme = android.R.style.Theme_Panel;
        }
        if (theme != 0) {
            mTheme = theme;
        }
    }

開頭已經講過了,style使用注意事項。通過這個方法,可以看到,在不設置theme,即為0的情況下,theme會被設置為android.R.style.Theme_Panel。

這還可以根據自己定義的Dialog樣式設置進來。


下面就是show方法,共有兩個:

    public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }

    public int show(FragmentTransaction transaction, String tag) {
        mDismissed = false;
        mShownByMe = true;
        transaction.add(this, tag);
        mViewDestroyed = false;
        mBackStackId = transaction.commit();
        return mBackStackId;
    }

雖然是兩種寫法,但實際上還是將自己添加到FragmentManager中而已。


有顯示,就是得有不顯示的代碼:

    public void dismiss() {
        dismissInternal(false);
    }

    public void dismissAllowingStateLoss() {
        dismissInternal(true);
    }

兩個方法都是調用了void dismissInternal(boolean allowStateLoss),只是傳參不一樣而已,看一下dismissInternal這個方法:

    void dismissInternal(boolean allowStateLoss) {
        if (mDismissed) {
            return;
        }
        mDismissed = true;
        mShownByMe = false;
        if (mDialog != null) {
            mDialog.dismiss();
            mDialog = null;
        }
        mViewDestroyed = true;
        if (mBackStackId >= 0) {
            getFragmentManager().popBackStack(mBackStackId,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
            mBackStackId = -1;
        } else {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.remove(this);
            if (allowStateLoss) {
                ft.commitAllowingStateLoss();
            } else {
                ft.commit();
            }
        }
    }

它做了幾件事:

1、調用dialog的dismiss方法

2、如果自己在後退棧中,就將自己從後退棧中移除掉(彈出)

3、如果自己不在後退棧中,就將自己從FragmentManager中移除掉。

關於commitAllowingStateLoss與commit的區別,網上有很多講解,這裡也不細說了。以後的FragmentManager中,會對它有更詳細的解釋。



今天就先寫到這裡,後面部分下次發布。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved