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

接上篇,繼續:


然後就是setShowsDialog(boolean showsDialog)方法。官方文檔是這樣解釋的:控制DialogFragment是否是一個dislog,如果設置爲false,則沒有dialog被創建出來,你可以把它當做一個普通的Fragemnt使用。

開頭提到了,mShowsDialog默認爲true,所以如果你把DialogFragment確實作爲一個Dialog使用,那大可不必調這個方法。當我看到OnCreate的方法時,就更加確定。(官方文檔上說了一種情況,需要手動調用它,這種情況及其少見,有興趣的可以自行去研究)。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public void setShowsDialog(boolean showsDialog) {  
  2.     mShowsDialog = showsDialog;  
  3. }  

來看onCreate方法:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.   
  5.     mShowsDialog = mContainerId == 0;  
  6.   
  7.     if (savedInstanceState != null) {  
  8.         mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL);  
  9.         mTheme = savedInstanceState.getInt(SAVED_THEME, 0);  
  10.         mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true);  
  11.         mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);  
  12.         mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1);  
  13.     }  
  14.       
  15. }  
mShowsDialog = mContainerId == 0;

沒錯,默認情況下,mContainerId就是0,所以mShowsDialog自然就是true;而當你在把它當成Fragment使用時,會爲其指定xml佈局中位置,所以,mContainerId也會不爲0,所以mShowsDialog自然就是false。


然後是LayoutInflater getLayoutInflater(Bundle savedInstanceState),這個方法被hide了,所以外部是調不到的。

簡單說一下這個getLayoutInflater方法,它的調用點是在onCreateView的時候,從先後順序來說getLayoutInflater在onCreateView之前。

摘自FragmentManager:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),null, f.mSavedFragmentState);  

getLayoutInflater方法如下:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /** @hide */  
  2. @Override  
  3. public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {  
  4.     if (!mShowsDialog) {  
  5.         return super.getLayoutInflater(savedInstanceState);  
  6.     }  
  7.   
  8.     mDialog = onCreateDialog(savedInstanceState);  
  9.     switch (mStyle) {  
  10.         case STYLE_NO_INPUT:  
  11.             mDialog.getWindow().addFlags(  
  12.                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |  
  13.                     WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);  
  14.             // fall through...  
  15.         case STYLE_NO_FRAME:  
  16.         case STYLE_NO_TITLE:  
  17.             mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);  
  18.     }  
  19.     if (mDialog != null) {  
  20.         return (LayoutInflater) mDialog.getContext().getSystemService(  
  21.                 Context.LAYOUT_INFLATER_SERVICE);  
  22.     }  
  23.     return (LayoutInflater) mActivity.getSystemService(  
  24.             Context.LAYOUT_INFLATER_SERVICE);  
  25. }  

如果不是Dialog,則調用Fragment自身的方法;否則,就先創建一個dialog,然後,根據之前設置的style,對dialog賦值。所以,setStyle這個方法調用,一定要在onCreateView之前。一般來講,都會放到onCreate中調用。

STYLE_NO_FRAME和STYLE_NO_TITLE都調用了mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

那它們兩個參數有什麼不同呢,答案就在開頭setStyle中,STYLE_NO_FRAME會再沒有theme的情況下,設置theme爲android.R.style.Theme_Panel。


然後就是onCreateDialog方法,你可以重寫這個方法,創建一個自己定義好的dialog。默認情況下,會自己創建一個Dialog。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public Dialog onCreateDialog(Bundle savedInstanceState) {  
  2.     return new Dialog(getActivity(), getTheme());  
  3. }  

再說一個onDismiss方法,沒錯,它是DialogInterface.OnDismissListener中的方法,DialogFragment實現了它。所以,在dialog不顯示後,會回調這個方法,然後再去調用自己的dismissInternal方法:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public void onDismiss(DialogInterface dialog) {  
  2.     if (!mViewDestroyed) {  
  3.         dismissInternal(true);  
  4.     }  
  5. }  

那麼,dialog什麼時候顯示出來?是在OnStart的時候:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public void onStart() {  
  3.     super.onStart();  
  4.     if (mDialog != null) {  
  5.         mViewDestroyed = false;  
  6.         mDialog.show();  
  7.     }  
  8. }  

而與其對應的生命週期方法onStop()時,則是將其先隱藏了。
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public void onStop() {  
  3.     super.onStop();  
  4.     if (mDialog != null) {  
  5.         mDialog.hide();  
  6.     }  
  7. }  

最後就是onDestroyView方法,它會將dialog銷燬。
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public void onDestroyView() {  
  3.     super.onDestroyView();  
  4.     if (mDialog != null) {  
  5.         mViewDestroyed = true;  
  6.         mDialog.dismiss();  
  7.         mDialog = null;  
  8.     }  
  9. }  


好了,以上就是DialogFragment源碼部分。


小結:

1、DialogFragment本質上說就是Fragment,只是其內部還有一個dialog而已。你既可以當它是Dialog使用,也可以把它作爲Fragment使用。

2、setStyle中,style的參數是不可以相互一起使用的,只能用一個,如果還不滿足你使用,可以通過設置theme來滿足。

3、setStyle的調用點,要放在onCreateView前,否則,設置的style和theme將不起作用!

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