以下所示:php
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);
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是否是很熟悉。沒錯,後面再深度解析這塊源碼思路……java
//第一種 //設置樣式時,使用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等等。android
重點看一下mShowsDialog這個參數,這個參數是Boolean值,mShowsDialog = mContainerId == 0;因此,默認狀況下,mContainerId就是0,因此mShowsDialog就是true;而當你在把它當成Fragment使用時,會爲其指定xml佈局中位置,那麼mContainerId也會不爲0,因此mShowsDialog就是false。git
@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); } }
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; } }
@NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { return new Dialog(getActivity(), getTheme()); }
共同點:這兩種顯示方式都是經過tag的方式將DialogFragment以事務的形式提交,不一樣的是第二種方式是採用已經建立過的transaction,而且他返回了一個int類型的數值mBackStackId,mBackStackId是幹什麼用的呢?github
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;
}面試
具體看下面代碼編程
@Override public void onStart() { super.onStart(); if (mDialog != null) { mViewDestroyed = false; mDialog.show(); } }
@Override
public void onStop() {
super.onStop();
if (mDialog != null) {
mDialog.hide();
}
}segmentfault
@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;
}
}markdown
第一種:鏈式編程,以下所示app
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()方法br/>@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
//第五步:看BackStackRecord類中看commit方法br/>@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);
}
}