一张图片胜过千言万语,这是我的问题:
最后三个首选项是分钟和秒的自定义时间选择器 其他设置是正常的SwitchPreference,RingTonePreference,ListPreference和EditTextPreference
这是我的偏好XML
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/pref_header_general">
<SwitchPreference
android:defaultValue="true"
android:key="@string/pref_key_turbo"
android:summaryOff="@string/pref_summaryOff_turbo"
android:summaryOn="@string/pref_summaryOn_turbo"
android:title="@string/pref_title_turbo" />
<ListPreference
android:defaultValue="1"
android:entries="@array/pref_distance_units_list_titles"
android:entryValues="@array/pref_distance_units_list_values"
android:key="@string/pref_key_distance_units"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_distance_units" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_header_advanced">
<EditTextPreference
android:defaultValue="100"
android:dialogMessage="@string/pref_distance_dialog_msg"
android:dialogTitle="@string/pref_distance_dialog_title"
android:inputType="number|numberDecimal"
android:key="@string/pref_key_distance"
android:summary="@string/pref_summary_distance"
android:title="@string/pref_title_distance" />
<!-- Allows the user to choose a ringtone -->
<RingtonePreference
android:defaultValue="content://settings/system/notification_sound"
android:key="@string/pref_key_default_ringtone"
android:ringtoneType="notification"
android:showDefault="true"
android:showSilent="true"
android:title="@string/pref_title_default_ringtone" />
<com.test.birenbaum.TimePickerPreference
android:defaultValue="@string/pref_default_first"
android:dialogMessage="@string/pref_default_first_dialog_msg"
android:dialogTitle="@string/pref_default_first_dialog_title"
android:key="@string/pref_key_default_first"
android:summary="@string/pref_summary_default_first"
android:title="@string/pref_title_default_first" />
<com.test.birenbaum.TimePickerPreference
android:defaultValue="@string/pref_default_value_retry"
android:dialogMessage="@string/pref_default_retry_dialog_msg"
android:dialogTitle="@string/pref_default_retry_dialog_title"
android:key="@string/pref_key_default_retry"
android:summary="@string/pref_summary_default_retry"
android:title="@string/pref_title_default_retry" />
<com.test.birenbaum.TimePickerPreference
android:defaultValue="@string/pref_default_value_off"
android:dialogMessage="@string/pref_default_off_dialog_msg"
android:dialogTitle="@string/pref_default_off_dialog_title"
android:key="@string/pref_key_default_off"
android:summary="@string/pref_summary_default_off"
android:title="@string/pref_title_default_off" />
<ListPreference
android:defaultValue="1"
android:entries="@array/pref_default_algo_list_titles"
android:entryValues="@array/pref_default_algo_list_values"
android:key="@string/pref_key_default_algo_mode"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:summary="@string/pref_summary_default_algo"
android:title="@string/pref_title_default_algo_mode" />
</PreferenceCategory>
</PreferenceScreen>
我没有把TimePickerPreference
代码放在这里,因为它很长
我没有在代码中的任何地方设置首选项布局,所以我希望与内置首选项一样,但是如上图所示,它是不同的。
有关自定义偏好项目的原因与常规偏好不同的任何想法?
按要求提供更多信息
public class TimePickerPreference extends DialogPreference {
private static final String TAG = "TimePickerPreference";
public static boolean DEBUG = true;
private static final String DEFAULT_VALUE = "0m0s";
private static final String DEFAULT_SUMMARY = "%s";
private static final String SPLIT_REGEX = "m|s";
private static final String MATCH_REGEX = "\\d+m[0-5]?\\ds";
private static final String TIME_FORMAT = "%dm%ds";
private static final int MAX_MINUTES = 30;
private static final int MIN_MINUTES = 0;
private static final int MAX_SECONDS = 59;
private static final int MIN_SECONDS = 0;
private int mSeconds;
private int mMinutes;
private NumberPicker mSecondsPicker;
private NumberPicker mMinutesPicker;
private String mDefaultValue;
private String mSummary;
private String mSummaryFormat;
public TimePickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
MyLog.pe(DEBUG, TAG, "+ Constructor TimePickerPreference(context:%s, attrs:%s, defStyleAttr:%d)", context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TimePickerPreference, 0, 0);
setTitle(a.getString(R.styleable.TimePickerPreference_android_title));
if (getTitle() == null) {
setTitle(TimePickerPreference.class.getSimpleName());
}
mSummary = a.getString(R.styleable.TimePickerPreference_android_summary);
if (mSummary == null) {
mSummary = DEFAULT_SUMMARY;
}
setSummary(mSummary);
// At this stage the summary is virgin, still in skeleton format (with %s)
setSummaryFormat(mSummary);
mDefaultValue = a.getString(R.styleable.TimePickerPreference_android_defaultValue);
if (mDefaultValue == null) {
mDefaultValue = DEFAULT_VALUE;
}
setDefaultValue(mDefaultValue);
a.recycle();
setDialogLayoutResource(R.layout.preference_dialog_timepicker);
setPositiveButtonText(R.string.save_button);
setNegativeButtonText(android.R.string.cancel);
MyLog.px(DEBUG, TAG, "- Constructor TimePickerPreference()");
}
public TimePickerPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimePickerPreference(Context context) {
this(context, null, 0);
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
MyLog.pe(DEBUG, TAG, "+ onSetInitialValue(restorePersistedValue:%s, defaultValue:%s)", restorePersistedValue, defaultValue);
String[] time;
if (restorePersistedValue) {
time = getPersistedString((String) defaultValue).split(SPLIT_REGEX);
// Assume persisted value is kosher
mMinutes = Integer.valueOf(time[0]);
mSeconds = Integer.valueOf(time[1]);
} else {
time = ((String) defaultValue).split(SPLIT_REGEX);
if (time.length == 2) {
// Enforce MIN-MAX boundaries
mMinutes = Math.max(MIN_MINUTES, Math.min(MAX_MINUTES, (Integer.valueOf(time[0]))));
mSeconds = Math.max(MIN_SECONDS, Math.min(MAX_SECONDS, (Integer.valueOf(time[1]))));
defaultValue = getTime();
persistString((String) defaultValue);
} else {
// Picker system default value, definitely kosher
time = DEFAULT_VALUE.split(SPLIT_REGEX);
mMinutes = Integer.valueOf(time[0]);
mSeconds = Integer.valueOf(time[1]);
persistString(DEFAULT_VALUE);
}
}
MyLog.px(DEBUG, TAG, "- onSetInitialValue()");
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
MyLog.pe(DEBUG, TAG, "* onGetDefaultValue(a:%s, index:%s)", a, index);
return a.getString(index);
}
// @Override
// protected View onCreateDialogView() {
// return super.onCreateDialogView();
// }
@Override
protected void onBindDialogView(View view) {
MyLog.pe(DEBUG, TAG, "+ onBindDialogView(view:%s)", view);
super.onBindDialogView(view);
TextView tvMessage = view.findViewById(R.id.tvMessage);
String message = (String) getDialogMessage();
if (message == null || message.isEmpty()) {
tvMessage.setVisibility(View.GONE);
} else {
tvMessage.setText(message);
}
mMinutesPicker = view.findViewById(R.id.minutesPicker);
mMinutesPicker.setMaxValue(MAX_MINUTES);
mMinutesPicker.setMinValue(MIN_MINUTES);
mSecondsPicker = view.findViewById(R.id.secondsPicker);
mSecondsPicker.setMaxValue(MAX_SECONDS);
mSecondsPicker.setMinValue(MIN_SECONDS);
mMinutesPicker.setValue(mMinutes);
mSecondsPicker.setValue(mSeconds);
MyLog.px(DEBUG, TAG, "- onBindDialogView()");
}
@Override
protected void onDialogClosed(boolean positiveResult) {
MyLog.pe(DEBUG, TAG, "+ onDialogClosed(positiveResult:%s)", positiveResult);
super.onDialogClosed(positiveResult);
if (positiveResult) {
String newValue = new StringBuilder()
.append(mMinutesPicker.getValue())
.append('m')
.append(mSecondsPicker.getValue())
.append('s')
.toString();
if (callChangeListener(newValue)) {
//noinspection ConstantConditions
setTime(newValue);
}
}
MyLog.px(DEBUG, TAG, "- onDialogClosed()");
super.onDialogClosed(positiveResult);
}
@Override
public void setDefaultValue(Object defaultValue) {
MyLog.pe(DEBUG, TAG, "* setDefaultValue(defaultValue:%s)", defaultValue);
super.setDefaultValue(defaultValue);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
MyLog.pe(DEBUG, TAG, "+ onRestoreInstanceState(state:%s)",state);
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
}
MyLog.px(DEBUG, TAG, "- onRestoreInstanceState()");
}
/**
* Save the instance state so that it will survive events like
* screen orientation change that may temporarily destroy it.
*/
@Override
protected Parcelable onSaveInstanceState() {
MyLog.pe(DEBUG, TAG, "+ onSaveInstanceState()");
final Parcelable superState = super.onSaveInstanceState();
Parcelable result;
if (isPersistent()) {
// No need to save instance state since it's persistent
result = superState;
} else {
final SavedState myState = new SavedState(superState);
myState.seconds = mSeconds;
myState.minutes = mMinutes;
result = myState;
}
MyLog.px(DEBUG, TAG, "- onSaveInstanceState()");
return result;
}
//----------------------------------------------------------------------------
public int getSeconds() {
return mSeconds;
}
public void setSeconds(int seconds) {
mSeconds = seconds;
}
public int getMinutes() {
return mMinutes;
}
public void setMinutes(int minutes) {
mMinutes = minutes;
}
public String getSummaryFormat() {
return mSummaryFormat;
}
public void setSummaryFormat(String summaryFormat) {
mSummaryFormat = summaryFormat;
}
@SuppressLint("DefaultLocale")
public String getTime() {
return String.format(TIME_FORMAT, mMinutes, mSeconds);
}
/**
* Saves the value to the {@link android.content.SharedPreferences SharedPreferences}.
*
* @param newTime A value to save. Must be in the correct format otherwise the save
* operation is not executed
*/
public void setTime(String newTime) {
MyLog.pe(DEBUG, TAG, "+ setTime(newTime:%s)", newTime);
final boolean wasBlocking = shouldDisableDependents();
if (newTime.matches(MATCH_REGEX)) {
String[] time = newTime.split(SPLIT_REGEX);
// No need to check for MAX and MIN values
// The values come from the spinners, therefore are within boundaries
mMinutes = Integer.valueOf(time[0]);
mSeconds = Integer.valueOf(time[1]);
persistString(newTime);
notifyChanged();
}
final boolean isBlocking = shouldDisableDependents();
if (isBlocking != wasBlocking) {
notifyDependencyChange(isBlocking);
}
MyLog.px(DEBUG, TAG, "- setTime()");
}
@Override
public String toString() {
return getTime();
}
//----------------------------------------------------------------------------
/**
* Returns the summary of this TimePickerPreference. If the summary
* has a {@linkplain java.lang.String#format String formatting}
* marker in it (i.e. "%s" or "%1$s"), then the current minutes and seconds
* value will be substituted in its place.
*
* @return the summary with appropriate string substitution
*/
@Override
public CharSequence getSummary() {
MyLog.pe(DEBUG, TAG, "+ getSummary()");
CharSequence result;
if (mSummary == null) {
result = super.getSummary();
} else {
result = String.format(mSummary, getTime());
}
MyLog.px(DEBUG, TAG, "- getSummary()");
return result;
}
/**
* Sets the summary for this Preference with a CharSequence.
* If the summary has a {@linkplain java.lang.String#format String formatting}
* marker in it (i.e. "%s" or "%1$s"), then the current entry value will be substituted
* in its place when it's retrieved.
*
* @param summary The summary for the preference.
*/
@Override
public void setSummary(CharSequence summary) {
MyLog.pe(DEBUG, TAG, "+ setSummary(summary:%s)", summary);
super.setSummary(summary);
if (summary == null && mSummary != null) {
mSummary = null;
} else if (summary != null && !summary.equals(mSummary)) {
mSummary = summary.toString();
}
MyLog.px(DEBUG, TAG, "- setSummary()");
}
//----------------------------------------------------------------------------
private static class SavedState extends BaseSavedState {
int seconds;
int minutes;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
MyLog.pe(DEBUG, TAG, "+ SavedState(source:%s)", source);
seconds = source.readInt();
minutes = source.readInt();
MyLog.px(DEBUG, TAG, "- SavedState()");
}
@Override
public void writeToParcel(Parcel dest, int flags) {
MyLog.pe(DEBUG, TAG, "+ writeToParcel(dest:%s, flags:%s)", dest, flags);
super.writeToParcel(dest, flags);
dest.writeInt(seconds);
dest.writeInt(minutes);
MyLog.px(DEBUG, TAG, "- writeToParcel()");
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
答案 0 :(得分:0)
问题是/是在偏好构造函数的第三个参数(defStyleAtttr
)中。
这是一个整数,但0不是默认值, com.android.internal.R.attr.dialogPreferenceStyle
是。
所以我删除了我的第三个构造函数;并让基类DialogPreference
处理defStylAttr
值。现在它显示出与其他内置偏好相同的风格。