Android UI篇——DialogFragment系列六之常見問題

《DialogFragment系列一之源碼分析》
《DialogFragment系列二之Dialog封裝》
《DialogFragment系列三之AlertDialog實(shí)現(xiàn)》
《DialogFragment系列四之StatusDialog(Progress搔谴、Success、Error)實(shí)現(xiàn)》
《DialogFragment系列五之ItemDialog(eg:BottomDialog)實(shí)現(xiàn)》
《DialogFragment系列六之常見問題》

前幾篇通過對(duì)DialogFragment的源碼分析定義了一個(gè)BaseDialog進(jìn)而實(shí)現(xiàn)了AlertDialog桩撮、StatusDialog敦第,在此期間遇到了幾個(gè)比較經(jīng)典的問題,與讀者分享一下店量。

問題一:onViewCreated()不回調(diào)

筆者想通過onViewCreated()來設(shè)置布局控件芜果,但是怎么也不回調(diào),以前一直使用Fragment都會(huì)回調(diào)垫桂,現(xiàn)在怎么不回調(diào)了呢?帶著疑問粟按,進(jìn)去看了一下源碼诬滩,發(fā)現(xiàn)了貓膩霹粥。首先看下onViewCreated()在哪里被調(diào)用了,看下源碼:

moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
   .......
   case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    ensureInflatedFragmentView(f);

                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(
                                            "Cannot create fragment "
                                                    + f
                                                    + " for a container view with no id"));
                                }
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    String resName;
                                    try {
                                        resName = f.getResources().getResourceName(f.mContainerId);
                                    } catch (NotFoundException e) {
                                        resName = "unknown";
                                    }
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + resName
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                //這里被調(diào)用
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                                // Only animate the view if it is visible. This is done after
                                // dispatchOnFragmentViewCreated in case visibility is changed
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            } else {
                                f.mInnerView = null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
   .......
}

通過查看源碼發(fā)現(xiàn)疼鸟,onViewCreate()在moveToState()中即performCreateView創(chuàng)建contentView之后被調(diào)用后控,進(jìn)入onViewCreate()方法要通過一個(gè)判斷語句f.mView != null,那我們看下f.mView 是哪來的空镜,繼續(xù)回溯源碼:

void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        mPerformedCreateView = true;
        mViewLifecycleOwner = new LifecycleOwner() {
            @Override
            public Lifecycle getLifecycle() {
                if (mViewLifecycleRegistry == null) {
                    mViewLifecycleRegistry = new LifecycleRegistry(mViewLifecycleOwner);
                }
                return mViewLifecycleRegistry;
            }
        };
        mViewLifecycleRegistry = null;
        //這里啊浩淘,在這里被賦值
        mView = onCreateView(inflater, container, savedInstanceState);
        if (mView != null) {
            // Initialize the LifecycleRegistry if needed
            mViewLifecycleOwner.getLifecycle();
            // Then inform any Observers of the new LifecycleOwner
            mViewLifecycleOwnerLiveData.setValue(mViewLifecycleOwner);
        } else {
            if (mViewLifecycleRegistry != null) {
                throw new IllegalStateException("Called getViewLifecycleOwner() but "
                        + "onCreateView() returned null");
            }
            mViewLifecycleOwner = null;
        }
 }

通過回溯源碼,發(fā)現(xiàn)mView在performCreateView()里被唯一賦值吴攒,而且來源就是平時(shí)熟悉的onCreateView()张抄,performCreateView()是在創(chuàng)建contentView使用,在moveToState()中先調(diào)用performCreateView()創(chuàng)建contentView洼怔,然后再調(diào)用onViewCreated()署惯。既然定位到了onCreateView()那去看看其返回值:

   @Nullable
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

Fragment中默認(rèn)返回null,而且Dialog中onCreateView()也使用Fragment的返回值,所以此時(shí)mView就會(huì)為null

    @Nullable
    @Override
    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //getDialog().setCancelable(setCancelable());
        getDialog().setCanceledOnTouchOutside(setCancelable());
        setCancelable(setCancelable());
        //設(shè)置背景透明
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return super.onCreateView(inflater, container, savedInstanceState);
    }

綜上镣隶,onViewCreated()不回調(diào)是因?yàn)閛nCreateView返回值為null极谊,但是在Dialog中沒有使用onCreateView去加載布局,是在onCreateDialog中加載的布局安岂,所以可以在onCreateDialog()中主動(dòng)回調(diào)onViewCreated()此問題就迎刃而解了轻猖。

   @NonNull
    @Override
    public final android.app.Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        View dialogLayout = LayoutInflater.from(getContext()).inflate(setLayoutRes(), null);
        builder.setView(dialogLayout);
        //主動(dòng)回調(diào)
        onViewCreated(dialogLayout, null);
        return builder.create();
    }
問題二:設(shè)置getDialog().setCancelable(setCancelable())后點(diǎn)擊返回鍵Dialog還是會(huì)dismiss

設(shè)置了getDialog().setCancelable(setCancelable())后點(diǎn)擊返回鍵Dialog還是會(huì)dismiss,很納悶域那,源碼里邏輯也是攔截返回事件通過boolean mCancelable來判斷是否dismiss咙边,代碼如下:

   public void onBackPressed() {
        if (mCancelable) {
            cancel();
        }
    }

真是百思不得其解,而后返回到DialogFragment查看琉雳,發(fā)現(xiàn)了一個(gè)相似的方法样眠,如下:

 boolean mCancelable = true;
 public void setCancelable(boolean cancelable) {
        mCancelable = cancelable;
        if (mDialog != null) mDialog.setCancelable(cancelable);
  }

罪魁禍?zhǔn)捉K于找到了,原來DialogFragment默認(rèn)設(shè)置了mCancelable翠肘,而默認(rèn)值是true檐束,所以導(dǎo)致了getDialog().setCancelable(setCancelable())不管作用,那可以直接通過DialogFragment的setCancelable()來設(shè)置束倍,代碼如下:

    @Nullable
    @Override
    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //getDialog().setCancelable(setCancelable());
        setCancelable(setCancelable());
        getDialog().setCanceledOnTouchOutside(setCancelable());
                //設(shè)置背景透明
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return super.onCreateView(inflater, container, savedInstanceState);
    }
    protected boolean setCancelable() {
        return dialogParams.isCancelable;
    }

到此被丧,此問題被解決

問題三:出現(xiàn)非contentView的背景

運(yùn)行代碼發(fā)現(xiàn)出現(xiàn)了非contentView的背景,此背景是DialogFragment的默認(rèn)背景绪妹,去掉即可甥桂,代碼如下:

@Nullable
    @Override
    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        getDialog().setCancelable(setCancelable());
        getDialog().setCanceledOnTouchOutside(setCancelable());
        setCancelable(setCancelable());
        //設(shè)置背景透明
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return super.onCreateView(inflater, container, savedInstanceState);
    }

以上就是在實(shí)現(xiàn)Dialog的過程遇到的三個(gè)問題以及解決辦法,特此記錄一下并分享給讀者邮旷!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末黄选,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌办陷,老刑警劉巖貌夕,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異民镜,居然都是意外死亡啡专,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門制圈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來们童,“玉大人,你說我怎么就攤上這事鲸鹦』劭猓” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵亥鬓,是天一觀的道長完沪。 經(jīng)常有香客問我,道長嵌戈,這世上最難降的妖魔是什么覆积? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮熟呛,結(jié)果婚禮上宽档,老公的妹妹穿的比我還像新娘。我一直安慰自己庵朝,他們只是感情好吗冤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著九府,像睡著了一般椎瘟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侄旬,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天肺蔚,我揣著相機(jī)與錄音,去河邊找鬼儡羔。 笑死宣羊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汰蜘。 我是一名探鬼主播仇冯,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼族操!你這毒婦竟也來了苛坚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泼舱,沒想到半個(gè)月后姐赡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柠掂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了依沮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涯贞。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖危喉,靈堂內(nèi)的尸體忽然破棺而出宋渔,到底是詐尸還是另有隱情,我是刑警寧澤辜限,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布皇拣,位于F島的核電站,受9級(jí)特大地震影響薄嫡,放射性物質(zhì)發(fā)生泄漏氧急。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一毫深、第九天 我趴在偏房一處隱蔽的房頂上張望吩坝。 院中可真熱鬧,春花似錦哑蔫、人聲如沸钉寝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嵌纲。三九已至,卻和暖如春腥沽,著一層夾襖步出監(jiān)牢的瞬間逮走,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工巡球, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留言沐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓酣栈,卻偏偏與公主長得像险胰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矿筝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容