DialogPreference 踩坑詳解

在學習這個之前,首先我們應該搞懂什麼是Preferences以及AlertDialog的詳細使用。懂的了這些之後我們在看看什麼是DialogPreference ,以及和他相關的ListPreferenceMultiSelectListPreference

1.ListPreference
顧名思義ListPreference就類似AlertDialogsetSingleChoiceItems功能,只是多了一項記憶功能。下面看一下主要代碼

@Override
    protected void onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);
        
        if (mEntries == null || mEntryValues == null) {
            throw new IllegalStateException(
                    "ListPreference requires an entries array and an entryValues array.");
        }

        mClickedDialogEntryIndex = getValueIndex();
        builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex, 
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        mClickedDialogEntryIndex = which;

                        /*
                         * Clicking on an item simulates the positive button
                         * click, and dismisses the dialog.
                         */
                        ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
                        dialog.dismiss();
                    }
        });
        
        /*
         * The typical interaction for list-based dialogs is to have
         * click-on-an-item dismiss the dialog instead of the user having to
         * press 'Ok'.
         */
        builder.setPositiveButton(null, null);
    }


 @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        
        if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
            String value = mEntryValues[mClickedDialogEntryIndex].toString();
            if (callChangeListener(value)) {
            	//這裏會記錄用戶的點擊項,存儲在默認的SharedPreferences中
                setValue(value);
            }
        }
    }

在這裏插入圖片描述

2.MultiSelectListPreference
顧名思義MultiSelectListPreference就類似AlertDialogsetMultiChoiceItems功能,只是多了一項記憶功能。下面看一下主要代碼

 @Override
    protected void onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);
        
        if (mEntries == null || mEntryValues == null) {
            throw new IllegalStateException(
                    "MultiSelectListPreference requires an entries array and " +
                    "an entryValues array.");
        }
        
        boolean[] checkedItems = getSelectedItems();
        builder.setMultiChoiceItems(mEntries, checkedItems,
                new DialogInterface.OnMultiChoiceClickListener() {
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        if (isChecked) {
                            mPreferenceChanged |= mNewValues.add(mEntryValues[which].toString());
                        } else {
                            mPreferenceChanged |= mNewValues.remove(mEntryValues[which].toString());
                        }
                    }
                });
        mNewValues.clear();
        mNewValues.addAll(mValues);
    }


 @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        
        if (positiveResult && mPreferenceChanged) {
            final Set<String> values = mNewValues;
            if (callChangeListener(values)) {
            	//這裏會記錄用戶的選擇項,存儲在默認的SharedPreferences中
                setValues(values);
            }
        }
        mPreferenceChanged = false;
    }

在這裏插入圖片描述

也許我們可能覺得這些功能用起來很簡單,系統幫我們做了存儲,省去了很多工作量。但是請用戶注意這裏有一個大坑,我們繼續跟進代碼:

    protected void showDialog(Bundle state) {
        Context context = getContext();

        mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
        
        mBuilder = new AlertDialog.Builder(context)
            .setTitle(mDialogTitle)
            .setIcon(mDialogIcon)
            .setPositiveButton(mPositiveButtonText, this)
            .setNegativeButton(mNegativeButtonText, this);

        View contentView = onCreateDialogView();
        if (contentView != null) {
            onBindDialogView(contentView);
            mBuilder.setView(contentView);
        } else {
            mBuilder.setMessage(mDialogMessage);
        }
        
        //重新該接口我們可以自定義ContentUI和TitleUI
        //builder.setAdapter,setCustomTitle
        onPrepareDialogBuilder(mBuilder);
        
        getPreferenceManager().registerOnActivityDestroyListener(this);
        
        //請注意這裏,這裏直接Create生成Dialog之後,並沒有給我們操作Dialog的機會
        //所以如果此時美工提出需要圓角界面,那麼由於我們無法獲取到Window,
        //只能通過AlertDialog自己實現類似功能了,之前覺得好用的的偷懶會因此付出代價
        // Create the dialog
        final Dialog dialog = mDialog = mBuilder.create();
        if (state != null) {
            dialog.onRestoreInstanceState(state);
        }
        if (needInputMethod()) {
            requestInputMethod(dialog);
        }
        dialog.setOnDismissListener(this);
        dialog.show();
    }

從這裏可以看出,showDialog只提供了重載onPrepareDialogBuilder修改 AlertDialog.Builder的機會,但是卻沒有提供修改dialog 實例的機會。也就是說我們可以通過重載onPrepareDialogBuilder,定製Content ViewTitle View,但是卻沒辦法獲取到Window,也就是說我們無法操作Window,導致無法實現圓角窗口。雖然這些控件看似提高了我們的工作效率,但是有些UI(圓角窗口)沒辦法實現。此時需要我們推翻之前的工作量,通過AlertDialog自定義UI實現上面控件類似功能,浪費很多時間(實際項目已採坑)。

坑坑坑:無法實現圓角窗口
在這裏插入圖片描述

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