Issue
I have a basic DatePicker
that's spinner-style, without any layouts. It looks like this:
class DatePickerFragment: DialogFragment(), DatePickerDialog.OnDateSetListener {
private lateinit var date: Date
interface Callbacks {
fun onDateSelected(date: Date)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
date = arguments?.getSerializable(ARG_DATE) as Date
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val calendar = Calendar.getInstance().apply {
time = date
}
val initialYear = calendar.get(Calendar.YEAR)
val initialMonth = calendar.get(Calendar.MONTH)
val initialDay = calendar.get(Calendar.DAY_OF_MONTH)
return DatePickerDialog(
requireContext(),
this,
initialYear,
initialMonth,
initialDay
)
}
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
val selectedDate = GregorianCalendar(year, month, dayOfMonth).time
targetFragment?.let { fragment ->
(fragment as Callbacks).onDateSelected(selectedDate)
}
}
companion object {
fun getInstance(date: Date): DatePickerFragment {
return DatePickerFragment().apply {
arguments = Bundle().apply {
putSerializable(ARG_DATE, date)
}
}
}
}
}
private const val ARG_DATE = "date"
The picker works as it should. The problem is that it displays the month name (three letter format), see:
How do I make the DatePicker to display months numerically (two-digit format)? In other words instead of Mar
it would display as 03
. Ideally, I'd like to avoid having to implement custom spinners, if possible.
Solution
You can achieve this by finding the month NumberPicker from DatePicker and setting the displayed values to numeric strings.
Make the below changes:
1.Create your DatePickerDialog in onCreateDialog(savedInstanceState: Bundle?)
using a custom Style like below:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val calendar = Calendar.getInstance().apply {
time = date
}
val initialYear = calendar.get(Calendar.YEAR)
val initialMonth = calendar.get(Calendar.MONTH)
val initialDay = calendar.get(Calendar.DAY_OF_MONTH)
val mPickerDialog: DatePickerDialog = object : DatePickerDialog(requireContext(), R.style.MyDatePickerDialogStyle, this, initialYear, initialMonth, initialDay) {
override fun onDateChanged(view: DatePicker, year: Int, month: Int, dayOfMonth: Int) {
super.onDateChanged(view, year, month, dayOfMonth)
setNumericMonth(view)
}
}
setNumericMonth(mPickerDialog.datePicker)
return mPickerDialog
}
where R.style.MyDatePickerDialogStyle
is a custom style to set the Spinner Style like below:
<style name="MyDatePickerDialogStyle" parent="android:Theme.Material.Dialog">
<item name="android:datePickerStyle">@style/MyDatePickerStyle</item>
</style>
<style name="MyDatePickerStyle" parent="android:Widget.Material.DatePicker">
<item name="android:datePickerMode">spinner</item>
</style>
2.Use the below helper functions in DatePickerFragment
to set month to be numeric like below:
private fun setNumericMonth(datePicker: DatePicker) {
val monthNumbers = arrayOf("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12")
val monthPicker = getMonthNumberPicker(datePicker)
if (monthPicker != null) {
monthPicker.displayedValues = monthNumbers
}
}
private fun getMonthNumberPicker(datePicker: DatePicker?): NumberPicker? {
try {
if (datePicker != null && datePicker.childCount > 0 && datePicker.getChildAt(0) is ViewGroup) {
val vg = datePicker.getChildAt(0) as ViewGroup
if (vg.childCount > 0 && vg.getChildAt(0) is ViewGroup) {
val vgPickers = vg.getChildAt(0) as ViewGroup
for (i in 0 until vgPickers.childCount) {
if (vgPickers.getChildAt(i) is NumberPicker && i == 1) {
return vgPickers.getChildAt(i) as NumberPicker
}
}
}
}
} catch (e: Exception) {
}
return null
}
Result:
Answered By - MariosP
Answer Checked By - Terry (JavaFixing Volunteer)