AndroidX中自定义DialogPreference和android framework以及support库的不太一样,翻了官网文档发现也没有介绍,网上几乎也搜索不到相关资料,于是只能翻了sdk源代码来寻找方法,特此记录,给有需要的同学。
案例
做一个设置界面,其中有一个设置项是用来选择时间,因为界面选择了PreferenceFragmentCompat
,所以最佳的做法就是自定义一个Preference,使得点击之后弹出一个TimePicker
用来选择时间。于是定下目标,自定义类TimePickerPreference
,实现点击弹出时间选择界面并自动保存值的效果。
实践
要完成任务,我们需要实现三个类,才能达到效果。
TimePickerPreference
在AndroidX中,官方把Preference的UI和数据部分分离了开来,而TimePickerPreference就是用来处理数据存储读取的。TimePickerPreference继承自androidx.preference.DialogPreference
。
public void setTime(int time) {
final boolean wasBlocking = shouldDisableDependents();
timeInMinute = time;
persistInt(time);
final boolean isBlocking = shouldDisableDependents();
if (isBlocking != wasBlocking) {
notifyDependencyChange(isBlocking);
}
showSummary();
notifyChanged();
}
public int getTime() {
return timeInMinute;
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, 0);
}
@Override
protected void onSetInitialValue(Object defaultValue) {
if (defaultValue == null)
defaultValue = 0;
setTime(getPersistedInt((Integer) defaultValue));
}
注意上面代码中的两个Override方法,这就是必须要实现的两个方法,当然,还有其它方法,比如onSaveInstanceState
之类的方法,文章最后会给出完整的源代码。
TimePickerDialogFragmentCompat
TimePickerDialogFragmentCompat负责UI层的构建,继承自androidx.preference.PreferenceDialogFragmentCompat
。
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
picker = view.findViewById(R.id.time_picker);
picker.setIs24HourView(true);
picker.setCurrentHour(timeInMinute / 60);
picker.setCurrentMinute(timeInMinute % 60);
}
private TimePickerPreference getTimePickerPreference() {
return (TimePickerPreference) getPreference();
}
@Override
public void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
final TimePickerPreference preference = getTimePickerPreference();
timeInMinute = calCurrentTime();
if (preference.callChangeListener(timeInMinute)) {
preference.setTime(timeInMinute);
}
}
}
同样注意上面代码中的两个Override方法,这就是必须要实现的两个方法,当然,也有其它方法,比如同样的onSaveInstanceState
之类的方法。注意,由于是负责构建UI的部分,其实它就是一个fragment,所以同样的,最好写一个newInstance方法用来构造对象,这样系统恢复此实例时会自动恢复其中的argument。文章的最后会给出完整的源代码。
MainFragment
最后就是我们用来展示自定义preference的界面了,假设叫MainFragment
,继承自androidx.preference.PreferenceFragmentCompat
,只要复写其中的一个方法就可以了。
@Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof TimePickerPreference) {
TimePickerDialogFragmentCompat f = TimePickerDialogFragmentCompat.newInstance(preference.getKey());
f.setTargetFragment(this, 0);
f.show(getFragmentManager(), TimePickerDialogFragmentCompat.FRAGMENT_TAG);
return;
}
super.onDisplayPreferenceDialog(preference);
}
大功告成
完整源码: