Reputation: 133
I am implementing a custom TimePicker
for setting a preference in a PreferenceFragmentCompat
fragment, following mainly this guide. While I have successfully made it work, the size of the Dialogs does not coincide with those of the same Dialog set in another Activity.
In the case of the TimePicker
the one in the PreferenceFragmentCompat
looks like this
While if I put a TimePicker
in any other Activity the looks is
For the case of DatePicker
, the result in the Fragment looks like the one in this question, and the solution proposed there does not work in my case.
Is there a way of having the Pickers in the PreferenceFragment
look like those in Activities? My implementation is the following:
styles.xml
<style name="Preference.App.DialogPreference" parent="Preference.Material">
<item name="positiveButtonText">@android:string/ok</item>
<item name="negativeButtonText">@android:string/cancel</item>
<item name="android:dialogTitle" />
</style>
SettingsActivity.kt
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preferences)
supportFragmentManager.beginTransaction().replace(R.id.container, SettingsFragment())
.commit()
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
override fun onDisplayPreferenceDialog(preference: Preference) {
// Try if the preference is one of our custom Preferences
val dialogFragment: DialogFragment? = when (preference) {
is TimePickerPreference -> {
// Create a new instance of TimePreferenceDialogFragment with the key of the related
// Preference
TimePickerPreferenceDialog.newInstance(preference.getKey())
}
else -> null
}
if (dialogFragment != null) {
// The dialog was created (it was one of our custom Preferences), show the dialog for it
dialogFragment.setTargetFragment(this, 0)
dialogFragment.show(
parentFragmentManager,
"androidx.preference.PreferenceFragmentCompat.DIALOG"
)
} else {
// Dialog creation could not be handled here. Try with the super method.
super.onDisplayPreferenceDialog(preference)
}
}
}
}
TimePickerPreference.kt
class TimePickerPreference @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.preferenceStyle,
defStyleRes: Int = defStyleAttr
) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
companion object {
private const val DEFAULT_VALUE = 0
}
var time: Int = DEFAULT_VALUE
set(value) {
field = value
// Save to SharedPreferences
persistInt(value)
}
override fun onGetDefaultValue(a: TypedArray?, index: Int): Any? {
// Default value from attribute. Fallback value is set to 0.
return a?.getInt(index, DEFAULT_VALUE) ?: DEFAULT_VALUE
}
override fun onSetInitialValue(defaultValue: Any?) {
// Read the value. Use the default value if it is not possible.
time = getPersistedInt((defaultValue as? Int) ?: DEFAULT_VALUE)
val hour = time / 60
val minute = time % 60
summary = "$hour:${if (minute < 10) "0$minute" else "$minute"}"
}
}
TimePickerPreferenceDialog.kt
class TimePickerPreferenceDialog : PreferenceDialogFragmentCompat() {
private lateinit var timePicker: TimePicker
override fun onCreateDialogView(context: Context?): View {
timePicker = TimePicker(context)
return timePicker
}
override fun onBindDialogView(view: View?) {
super.onBindDialogView(view)
// Get the time from the related Preference
val minutesAfterMidnight: Int = preference.time
// Set the time to the TimePicker
val hours = minutesAfterMidnight / 60
val minutes = minutesAfterMidnight % 60
val is24hour = DateFormat.is24HourFormat(context)
timePicker.apply {
setIs24HourView(is24hour)
if (Build.VERSION.SDK_INT >= 23) {
hour = hours
minute = minutes
} else {
@Suppress("DEPRECATION")
currentHour = hours
@Suppress("DEPRECATION")
currentMinute = minutes
}
}
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
val hours: Int
val minutes: Int
// Get the current values from the TimePicker
if (Build.VERSION.SDK_INT >= 23) {
hours = timePicker.hour
minutes = timePicker.minute
} else {
@Suppress("DEPRECATION")
hours = timePicker.currentHour
@Suppress("DEPRECATION")
minutes = timePicker.currentMinute
}
// Generate value to save
val minutesAfterMidnight = hours * 60 + minutes
// Save the value
preference.apply {
// This allows the client to ignore the user value.
if (callChangeListener(minutesAfterMidnight)) {
// Save the value
time = minutesAfterMidnight
}
}
preference.summary = "$hours:${if (minutes < 10) "0$minutes" else "$minutes"}"
}
}
override fun getPreference(): TimePickerPreference {
return super.getPreference() as? TimePickerPreference
?: error("Preference is not a TimePreference")
}
companion object {
fun newInstance(key: String?) = TimePickerPreferenceDialog().apply {
arguments = Bundle(1).apply {
putString(ARG_KEY, key)
}
}
}
}
Thank you very much
Upvotes: 2
Views: 492