此包下的類主要以Preference為父類,PreferenceActivity繼承自ListActivity用來顯示UI,以ListView形式顯示,preference主要用來做設定檔,所做的選擇以Sharedpreference(xml)形式存於程式目錄下。
使用方式:定義一個xml(隨便放哪,最好在res下建個xml檔案夾,放裡面)檔案,在java代碼中addPreferencesFromResource(int res),最基本的preference就完成了。
也可以
PreferenceManager pm = getPreferenceManager();PreferenceScreen screen = pm.createPreferenceScreen(this);setPreferenceScreen(screen);
設定根View。
xml檔案內以PreferenceScreen作為根節點,比如:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <ListPreference android:entryValues="@array/r" android:entries="@array/r" android:title="qqqqqqqq" android:summary="wwwwwwwwww" android:dialogTitle="hhh" android:key="55"/> <CheckBoxPreference /> </PreferenceScreen>
Preference :所有preference的父類,其屬性子類繼承
XML屬性:
android:key 用於儲存、取出資料的key。
android:title
用於顯示的標題,標題在上面一行,最多有兩行。
android:summary 摘要,配置的簡要說明,顯示在標題下面
android:selectable 是否能點取選擇,設定false則此條preference不可選(lose
focus)
android:enabled
是否起作用,false則能點取,但是不作用(有焦點)
android:shouldDisableView
當enabled設定為false,此屬性設定為true時,preference所代表的item變暗
android:layout
自訂item的View
DialogPreference:彈dialog的preference的父類,不直接在XML檔案中定義,而用其子類。繼承自Preference
android:dialogIcon
彈出的dialog的表徵圖
android:dialogMessage
dialog的訊息
android:dialogTitle dialog的標題
android:negativeButtonText
dialog的取消按鈕上面的文字
android:positiveButtonText
dialog的確定按鈕上的文字
android:dialogLayout 自訂dialog布局
ListPreference:點擊後彈dialog,dialog內是個單選ListView。繼承自DialogPreference
XML屬性:
android:entries
用於顯示的數組,彈出來的Dialog中ListView所顯示的內容
android:entryValues 被選取後所得到的資料,數組,對應entries。
不能設定dialogMessage,否則ListView將被Message內容覆蓋。
EditTextPreference:點擊後彈dialog,dialog的View部分是個EditText。繼承自DialogPreference
XML屬性:沒有專屬屬性
TwoStatePreference:代表兩種狀態轉換的配置類,不直接用,而用其子類
XML屬性:沒有專屬屬性
CheckBoxPreference: 帶checkbox的item,點擊後checkbox狀態改變。4.0繼承自TwoStatePreference,2.3繼承自Preference
XML屬性:
android:summaryOff 當checkbox狀態為false時,顯示的摘要內容
android:summaryOn 當checkbox狀態為true時,顯示的摘要內容
PreferenceCategory:對preference進行分組。
XML屬性:沒有專屬屬性
源碼分析:
當點擊Preference的Item時,首先觸發方法:performClick(PreferenceScreen preferenceScreen)
void performClick(PreferenceScreen preferenceScreen) { if (!isEnabled()) { return; } onClick(); if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { return; } PreferenceManager preferenceManager = getPreferenceManager(); if (preferenceManager != null) { PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager .getOnPreferenceTreeClickListener(); if (preferenceScreen != null && listener != null && listener.onPreferenceTreeClick(preferenceScreen, this)) { return; } } if (mIntent != null) { Context context = getContext(); context.startActivity(mIntent); } }
很明顯,如果設定了setEnable(false),後面所有代碼都失去作用了。
onClick()是個protect的空方法,留給子類用的。下面的這一段代碼決定了監聽事件的響應,如果設定了監聽,那麼點擊時調用監聽事件得到傳回值,如果返回true,則後面的代碼不執行了,false則繼續執行。
if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { return; }
下面一段代碼決定了點擊後跳轉到另一個Activity。
if (mIntent != null) { Context context = getContext(); context.startActivity(mIntent); }
其中mIntent可通過setIntent(Intent intent)方法設定,也可在布局檔案中如下設定
<Preference android:title="@string/ua_settings" > <intent android:action="android.intent.action.webview" android:targetClass="com.yeezone.engtest.Uaagent" android:targetPackage="com.yeezone.engtest" /> </Preference>
源碼版本2.3:
CheckboxPreference:
實現父類Preference的onclick方法:
@Override protected void onClick() { super.onClick(); boolean newValue = !isChecked(); // in onBindView() an AccessibilityEventViewClickedType is sent to announce the change // not sending mSendAccessibilityEventViewClickedType = true; if (!callChangeListener(newValue)) { return; } setChecked(newValue); }
其中callChangeListener(newValue)方法代碼如下:
protected boolean callChangeListener(Object newValue) { return mOnChangeListener == null ? true : mOnChangeListener.onPreferenceChange(this, newValue); }
上面這個方法中可以看出,如果對這個Preference進行了Preference.OnPreferenceChangeListener監聽,並且監聽的傳回值為true那麼後面的代碼將不會再執行。
setChecked(newValue)方法會把newValue存到設定檔中去。
DialogPreference:不直接使用,而是作為父類使用
實現父類Preference的onclick方法:
@Override protected void onClick() { showDialog(null); }
其中showDialog方法主要用來構建並顯示一個AlertDialog,並且調用onPrepareDialogBuilder(mBuilder);方法,並且對Dialog實現dissmiss監聽,在onDismiss方法中調用方法onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);,onPrepareDialogBuilder與onDialogClosed是空方法,留給子類實現。showDialog代碼如下:
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); } onPrepareDialogBuilder(mBuilder); getPreferenceManager().registerOnActivityDestroyListener(this); // Create the dialog final Dialog dialog = mDialog = mBuilder.create(); if (state != null) { dialog.onRestoreInstanceState(state); } if (needInputMethod()) { requestInputMethod(dialog); } dialog.setOnDismissListener(this); dialog.show(); }
從上面代碼中可以看出,如果 View
contentView = onCreateDialogView();得到的contentView 是個null則Dialog為一個簡短訊息的Dialog,不為null還是個簡短訊息的Dialog,不過樣式不同了。可繼承DialogPreference,重寫onCreateDialogView()方法來達到控制Dialog顯示的目的。
protected View onCreateDialogView() { if (mDialogLayoutResId == 0) { return null; } LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); return inflater.inflate(mDialogLayoutResId, null); }
EditTextPreference:繼承DialogPreference
重寫了onPrepareDialogBuilder(mBuilder)方法,把Dialog的View部分變成了一個EditText。沒有從寫onPrepareDialogBuilder(mBuilder)方法,重寫了onDialogClosed方法,代碼如下:
@Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); if (positiveResult) { String value = mEditText.getText().toString(); if (callChangeListener(value)) { setText(value); } } }
從上面的代碼可以看出,此方法被調時,如果參數 是true並且callChangeListener(value)返回true,則儲存變化的值到設定檔中,若且唯若點擊了確定按鈕時才會傳true。callChangeListener方法說明在CheckboxPreference部分。
ListPreference:繼承DialogPreference
重寫了onPrepareDialogBuilder與onDialogClosed方法,onPrepareDialogBuilder代碼如下:
@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); }
代碼比較容易懂。
onDialogClosed代碼如下:
@Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) { String value = mEntryValues[mClickedDialogEntryIndex].toString(); if (callChangeListener(value)) { setValue(value); } } }
原理參見前面解釋。