在学习这个之前,首先我们应该搞懂什么是Preferences以及AlertDialog的详细使用。懂的了这些之后我们在看看什么是DialogPreference
,以及和他相关的ListPreference
,MultiSelectListPreference
。
1.ListPreference
顾名思义ListPreference就类似AlertDialog
的setSingleChoiceItems
功能,只是多了一项记忆功能。下面看一下主要代码
@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就类似AlertDialog
的setMultiChoiceItems
功能,只是多了一项记忆功能。下面看一下主要代码
@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 View和Title View,但是却没办法获取到Window,也就是说我们无法操作Window,导致无法实现圆角窗口。虽然这些控件看似提高了我们的工作效率,但是有些UI(圆角窗口)没办法实现。此时需要我们推翻之前的工作量,通过AlertDialog自定义UI实现上面控件类似功能,浪费很多时间(实际项目已采坑)。
坑坑坑:无法实现圆角窗口