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实现上面控件类似功能,浪费很多时间(实际项目已采坑)。

坑坑坑:无法实现圆角窗口
在这里插入图片描述

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