設計自己的Android Preference
SeekBar Preference
Android提供了Preference供應用可以進行功能設置以及屬性配置等操作,檢查android.preference可以看到Preference下有若干子類,例如常用的EditTextPreference、
CheckBoxPreference、ListPreference等。但是僅僅有這些是不夠的。
在我現在的工作當中,應用裏有這麼一個場景,用戶手指在屏幕滑動,應用繪製出移動的軌跡。
熟悉Android API Demo(可以在SDK/platforms/android-1.5/samples下找到)的人一定記得在graphics目錄下,有一個FingerPaint的類實現了類似上述功能。但是還遠遠實現
不了我們的需要,–需求是要在Preference中實現挑選顏色和調整粗細。
當然,他山之石可以攻玉,FingerPaint還是提供了不錯的例子,尤其是FingPaint中選擇顏色所使用的另外一個類ColorPickerDialog基本上具備了我們想要的部分功能。
除了上面提到的FingerPaint之外,還可以從Android的源碼中找到可以參考的代碼。從framework/base/core/java中,找到android.preference包,可以看到有一個
SeekBarPreference的類,–這是一個“爛尾”類,代碼未完成,因此被Google打上了@hide的標籤。因此需要稍加完善,才能加以使用。
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
bar = (SeekBar) view.findViewById(R.id.seekbar);
bar.setOnSeekBarChangeListener(this);
bar.setProgress(barValue);
}
public void setValue(int value) {
barValue = value;
}
public int getValue() {
return barValue;
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
this.getOnPreferenceChangeListener().onPreferenceChange(this, barValue);
}
}
Color Picker Preference
在這個類的改造過程中,override兩個父類方法是關鍵所在,一個是onBindDialogView,另一個是onDialogClosed。
通過第一個方法,我們可以“找到”被當做content view的SeekBar的實例,進而可以獲得到其progress。
通過第二個方法,我們可以方便的通知到Listener,告訴它,SeekBar的值有變化。這裏我們把SeekBar的值,即progress看做是SeekBarPreference的value。除了這兩個方法之外,就是要增加setValue和getValue兩個方法了。
如果不看代碼的話,就會有疑問:SeekBar是如何進入Diglog的呢?它正式通過DialogPreference的屬性android:dialogLayout得以注入:
<net.poemcode.android.config.SeekBarPreference
android:key="@string/setting_handwrite_width_key"
android:title="@string/setting_handwrite_width_title"
android:dialogTitle="@string/setting_handwrite_width_title"
android:dialogLayout="@layout/setting_widthseekbar"
android:persistent="true"/>
依此原理,可以舉一反三,對於如何實現選擇顏色是不是有了思路?
首先實現一個視圖,負責展現不同顏色和接收用戶選中的顏色,其可以從SeekBarPreference中的內部類ColorPickerView加以改造完成;然後新增一個佈局文件,將剛纔的視圖加入到佈局當中;接着繼承DialogPreference實現自己的Preference子類ColorPickerPreference;最後在XML文件裏增加這個Preference並把剛纔的佈局文件通過dialogLayout屬性加入進去。從而實現了整個功能。
public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {
private static final String TAG = "SeekBarPreference";
private SeekBar bar;
private int barValue;
public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
bar = (SeekBar) view.findViewById(R.id.seekbar);
bar.setOnSeekBarChangeListener(this);
bar.setProgress(barValue);
}
public void setValue(int value) {
barValue = value;
}
public int getValue() {
return barValue;
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
this.getOnPreferenceChangeListener().onPreferenceChange(this, barValue);
}
}
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Log.d(TAG, "onProgressChanged, progress : " + progress + ", fromUser : " + fromUser);
}
public void onStartTrackingTouch(SeekBar seekBar) {
Log.d(TAG, "onStartTrackingTouch");
}
public void onStopTrackingTouch(SeekBar seekBar) {
barValue = seekBar.getProgress();
}
}