1.最簡單的使用方法php
2.源碼分析java
5.常見問題總結android
03.DialogFragment源碼分析github
07.彈窗常見問題segmentfault
以下所示:markdown
public class CustomDialogFragment extends DialogFragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //設置樣式 setStyle(DialogFragment.STYLE_NO_TITLE, R.style.CenterDialog); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.view_fragment_dialog, container, false); } public static void showDialog(FragmentActivity activity){ CustomDialogFragment customDialogFragment = new CustomDialogFragment(); customDialogFragment.show(activity.getSupportFragmentManager(),"yc"); } } //而後一行代碼調用 CustomDialogFragment.showDialog(this);
1.2.1 建立theme主題樣式,而且進行設置app
STYLE_NORMAL:會顯示一個普通的dialog STYLE_NO_TITLE:不帶標題的dialog STYLE_NO_FRAME:無框的dialog STYLE_NO_INPUT:沒法輸入內容的dialog,即不接收輸入的焦點,並且觸摸無效。
1.2.4 如何去掉標題欄,也許你會問,爲何第二種要在super.onActivityCreated(savedInstanceState)以前設置呢。這個是由於,看了源碼以後才知道onActivityCreated這個方法中,有mDialog.setContentView(view)這一步,說到setContentView是否是很熟悉。沒錯,後面再深度解析這塊源碼思路……
//第一種 //設置樣式時,使用STYLE_NO_TITLE setStyle(DialogFragment.STYLE_NO_TITLE, R.style.CenterDialog); //第二種 @Override public void onActivityCreated(Bundle savedInstanceState) { Window window = getDialog().getWindow(); if(window!=null){ window.requestFeature(Window.FEATURE_NO_TITLE); } super.onActivityCreated(savedInstanceState); }
onCreate這個方法主要是保存一些屬性狀態,好比style樣式,theme注意,是否能夠取消,後退棧的ID等等。
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mShowsDialog = mContainerId == 0; if (savedInstanceState != null) { mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL); mTheme = savedInstanceState.getInt(SAVED_THEME, 0); mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true); mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog); mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1); } }
mShowsDialog這個參數的做用
這個方法很重要呢,注意是設置對話框的基本外觀和設置主題等等。經過手動設置Dialog和Window能夠實現相同的效果,若是是在對話框建立以後調用它將會失去做用……
public void setStyle(@DialogStyle int style, @StyleRes int theme) { mStyle = style; if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) { mTheme = android.R.style.Theme_Panel; } if (theme != 0) { mTheme = theme; } }
該方法的做用主要是:當DialogFragment依附的Activity被建立的時候調用,此時fragment的活動窗體被初始化
onCreateDialog方法,你能夠重寫這個方法,建立一個本身定義好的dialog。默認狀況下,會本身建立一個Dialog。
@NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { return new Dialog(getActivity(), getTheme()); }
共同點:這兩種顯示方式都是經過tag的方式將DialogFragment以事務的形式提交,不一樣的是第二種方式是採用已經建立過的transaction,而且他返回了一個int類型的數值mBackStackId,mBackStackId是幹什麼用的呢?
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; }
在源碼中能夠看到這兩個方法都調用了dismissInternal(boolean)方法,不一樣的是傳入的boolean值一個爲false一個爲true,那麼究竟這個boolean起到什麼做用呢?
具體看下面代碼
@Override public void onStart() { super.onStart(); if (mDialog != null) { mViewDestroyed = false; mDialog.show(); } } @Override public void onStop() { super.onStop(); if (mDialog != null) { mDialog.hide(); } } @Override public void onDestroyView() { super.onDestroyView(); if (mDialog != null) { // Set removed here because this dismissal is just to hide // the dialog -- we don't want this to cause the fragment to // actually be removed. mViewDestroyed = true; mDialog.dismiss(); mDialog = null; } }
第一種:鏈式編程,以下所示
BottomDialogFragment.create(getSupportFragmentManager()) .setViewListener(new BottomDialogFragment.ViewListener() { @Override public void bindView(View v) { } }) .setLayoutRes(R.layout.dialog_bottom_layout_list) .setDimAmount(0.5f) .setTag("BottomDialog") .setCancelOutside(true) .setHeight(getScreenHeight() / 2) .show();
第二種:直接繼承,能夠高度定製本身想要的彈窗
public class ADialog extends BaseDialogFragment { @Override protected boolean isCancel() { return false; } @Override public int getLayoutRes() { return 0; } @Override public void bindView(View v) { } }
報錯日誌以下:
lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1493)
出現該問題的緣由
追蹤報錯日誌的來源
//第一步: public FragmentManager getSupportFragmentManager() { return mFragments.getSupportFragmentManager(); } //第二步: public FragmentManager getSupportFragmentManager() { return mHost.getFragmentManagerImpl(); } //第三步: FragmentManagerImpl getFragmentManagerImpl() { return mFragmentManager; } //第四步:看beginTransaction()方法 @Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); } //第五步:看BackStackRecord類中看commit方法 @Override public int commit() { return commitInternal(false); } @Override public int commitAllowingStateLoss() { return commitInternal(true); } //第六步:能夠看到這倆函數的區別就是commitInternal()方法中參數一個爲true,一個爲false int commitInternal(boolean allowStateLoss) { if (mCommitted) throw new IllegalStateException("commit already called"); if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "Commit: " + this); LogWriter logw = new LogWriter(TAG); PrintWriter pw = new PrintWriter(logw); dump(" ", null, pw, null); pw.close(); } mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; } //第七步:再追蹤到enqueueAction(this,allowStateLoss) public void enqueueAction(OpGenerator action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || mHost == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<>(); } mPendingActions.add(action); scheduleCommit(); } } //第八步:checkStateLoss()方法,這裏能夠看到拋出的錯誤日誌呢 private void checkStateLoss() { if (mStateSaved) { throw new IllegalStateException( "Can not perform this action after onSaveInstanceState"); } if (mNoTransactionsBecause != null) { throw new IllegalStateException( "Can not perform this action inside of " + mNoTransactionsBecause); } }