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;}@Overrideprotected Object onGetDefaultValue(TypedArray a, int index) {return a.getInt(index, 0);}@Overrideprotected void onSetInitialValue(Object defaultValue) {if (defaultValue == null)defaultValue = 0;setTime(getPersistedInt((Integer) defaultValue));}
注意上面代码中的两个Override方法,这就是必须要实现的两个方法,当然,还有其它方法,比如
onSaveInstanceState
之类的方法,文章最后会给出完整的源代码。
TimePickerDialogFragmentCompat
TimePickerDialogFragmentCompat负责UI层的构建,继承自
androidx.preference.PreferenceDialogFragmentCompat
。
@Overrideprotected 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();}@Overridepublic 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
,只要复写其中的一个方法就可以了。
@Overridepublic 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);}
大功告成
完整源码:
- TimePickerPreference
- TimePickerDialogFragmentCompat
- MainFragment