Date Picker¶
The Date Picker component provides a visual interface for picking a date or a date range.
It is a dialog that provides multiple options for navigating and selecting dates, including a
FioriCalendar, text input fields, year selection menu, and header and footer buttons.
Date Picker:

Date Input:

Date Range Picker:

Date Range Input:

Year Selector:

Using the Date Picker¶
Main API¶
The DatePicker composable function contains the dialog with date picking functionalities. The
API is as follows:
@Composable
fun DatePicker(
modifier: Modifier = Modifier,
state: FioriDatePickerState = rememberFioriDatePickerState(),
pickerOpened: Boolean,
updatePickerOpened: (Boolean) -> Unit,
updatePickedDateString: ((String) -> Unit)? = null,
updateDateCleared: ((Boolean) -> Unit)? = null,
supportText: String = stringResource(R.string.date_picker_support),
rangeSupportText: String = stringResource(R.string.date_picker_range_support),
pickerFormatter: String = "E, MMM d",
rangeFormatter: String = "MMM d",
useInput: Boolean = false,
useRange: Boolean = false,
onDateClicked: ((Date, FioriDatePickerState, FioriCalendarState) -> Unit)? = null,
onDateCleared: ((FioriDatePickerState) -> Unit)? = null,
onNegativeButtonClicked: ((FioriDatePickerState) -> Unit)? = null,
onPositiveButtonClicked: ((FioriDatePickerState) -> Unit)? = null,
onCancel: ((FioriDatePickerState) -> Unit)? = null,
colors: DatePickerColors = DatePickerDefaults.colors(),
textStyles: DatePickerTextStyles = DatePickerDefaults.textStyles(),
styles: DatePickerStyles = DatePickerDefaults.styles()
)
This API creates a Date Picker with the default configuration, which is single date selection
mode in calendar view with no date selected. The FioriDatePickerState class consists of a
FioriCalendarData object that allows application developers to configure certain parts of the
calendar view as per their own requirements. See Fiori Calendar for more details
on how FioriCalendar can be configured.
class FioriDatePickerState(
val data: FioriCalendarData = FioriCalendarData()
)
A function that remembers the FioriDatePickerState is also provided, which can be used when
the parameters of the FioriCalendarData class are not expected to change after initialization.
@Composable
fun rememberFioriDatePickerState(
data: FioriCalendarData = FioriCalendarData()
): FioriDatePickerState = rememberSaveable(saver = FioriDatePickerState.Saver()) {
FioriDatePickerState(data)
}
Note that certain parameters of the FioriCalendarData object will not be customizable for the
DatePicker component. The following parameters are not customizable:
FioriCalendarData(
viewType = /** ViewType.SCROLL or ViewType.MONTH depending on the useRange parameter */,
showOutOfMonthDates = false,
showMonthViewInLandscapeMode = true,
isSelectionPersistent = true,
headerData = HeaderData(enabled = false)
)
API Parameters¶
Some of the parameters are explained in more detail below.
Picker Opened¶
The pickerOpened parameter determines whether the Date Picker dialog is opened or not.
Update Picker Opened¶
The updatePickerOpened parameter is a function that is called when the Date Picker changes
its opened state. The Boolean that is returned should be used to update the pickerOpened parameter.
Update Picked Date String¶
The updatePickedDateString parameter is a function that is called when the user selects a
date. The formatted selected date or date range is returned as a String.
Update Date Cleared¶
The updateDateCleared parameter is a function that is called when the date cleared state is
changed, whether through clearing the date selection or successfully selecting a date. The
Boolean that is returned represents whether the date selection is cleared or not.
Support Text¶
The Date Picker component contains text at the top of the dialog that should describe the
purpose of the Date Picker when selecting a single date. This text can be customized using the
supportText parameter.
Range Support Text¶
The Date Picker component contains text at the top of the dialog that should describe the
purpose of the Date Picker when using range selection. This text can be customized using the
rangeSupportText parameter.
Picker Formatter¶
The pickerFormatter parameter is a String that represents the format of the selected date
shown as the header text when using the Date Picker. The default format is "E, MMM d".
Range Formatter¶
The rangeFormatter parameter is a String that represents the format of the selected start and
end dates shown as the header text when using range selection. The default format is "MMM d".
Use Input¶
The Date Picker can be initialized with either the calendar view displayed or the text input
fields displayed. The text input fields will be initially displayed if the useInput
parameter is set to true.
Use Range¶
The Date Picker can be used for either single date selection or date range selection. Date
range selection is enabled when the useRange parameter is set to true. When using date
range selection, the FioriCalendar will be displayed in scroll view mode.
On Date Clicked¶
The onDateClicked parameter can be used to notify when a date has been clicked. It returns
the clicked date as a Date object in the callback, along with the FioriDatePickerState and
the FioriCalendarState used in the Date Picker. Note that this is only invoked when the
application user taps on a date to select it.
On Date Cleared¶
The onDateCleared parameter can be used to notify when the date selection is cleared. It
returns the FioriDatePickerState used in the Date Picker.
On Negative Button Clicked¶
The onNegativeButtonClicked parameter can be used to notify when the negative button is
clicked. It returns the FioriDatePickerState used in the Date Picker.
On Positive Button Clicked¶
The onPositiveButtonClicked parameter can be used to notify when the positive button is
clicked. It returns the FioriDatePickerState used in the Date Picker.
On Cancel¶
The onCancel parameter can be used to notify when the Date Picker is canceled through the
upper icon button in the header when using range selection. It returns the FioriDatePickerState
used in the Date Picker.
Code Samples¶
Default Date Picker¶
This code snippet demonstrates the simplest use of the Date Picker initialized with default values. It creates a Date Picker in calendar view using single date selection with no selected date.
var pickerOpened by rememberSaveable { mutableStateOf(false) }
val updatePickerOpened: (Boolean) -> Unit = {
pickerOpened = it
}
DatePicker(
pickerOpened = pickerOpened,
updatePickerOpened = updatePickerOpened
)
Date Range Picker With Disabled Dates and Returned Range¶
This code snippet demonstrates how to create a Date Picker with disabled dates and how to retrieve
the selected date range through the pickedRange property of the FioriDatePickerState object.
Fridays are considered disabled and will not appear in the list of picked dates.
DatePicker(
state = FioriDatePickerState(
FioriCalendarData(
isDateDisabled = {
// getCalendar() implementation can be found in the Util.kt file for Fiori Calendar
val currentCal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
currentCal.time = it
currentCal.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY
}
)
),
useRange = true,
onPositiveButtonClicked = { state ->
val formatter = SimpleDateFormat("dd MMMM yyyy", getCurrentLocale())
val pickedRangeString = state.pickedRange.value.joinToString("\n") { date -> formatter.format(date) }
println("Picked dates: \n$pickedRangeString")
}
)
Custom Range Selection Behavior (Cannot Cross Disabled Dates)¶
This code snippet demonstrates how to create a Date Picker with customized behavior for range selection. The Date Picker will not allow the user to select a date range that crosses disabled dates by setting the selectable upper bound date to the next disabled date after the selected start date. Successfully selecting an end date, clearing the date selection, or closing the Date Picker will reset the end date to the default value, allowing any non-disabled date to be selected again.
// getDefaultStartEndDate() implementation can be found in the Util.kt file for Fiori Calendar
var endDate by rememberSaveable { mutableStateOf(getDefaultStartEndDate(getCurrentLocale(), false)) }
val disabledDates = ArrayList<Date>()
val cal = getCalendar(getCurrentLocale())
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 3)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 10)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 15)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 21)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 27)
disabledDates.add(cal.time)
val isDateDisabled: (Date) -> Boolean = {
var isDisabled = false
// getCalendar() implementation can be found in the Util.kt file for Fiori Calendar
val currentCal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
currentCal.time = it
val disabledCal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
for (date in disabledDates) {
disabledCal.time = date
// isSameDate() implementation can be found in the Util.kt file for Fiori Calendar
if (isSameDate(currentCal, disabledCal)) {
isDisabled = true
}
}
isDisabled || it > endDate
}
DatePicker(
state = FioriDatePickerState(
FioriCalendarData(
useRangeSelection = true,
isDateDisabled = isDateDisabled
)
),
rangeSupportText = "Select range without crossing disabled dates",
useRange = true,
onDateClicked = { date, state, _ ->
val nextDisabledDateIndex = findNextDisabledDateIndex(date, disabledDates)
endDate = if (state.rangePickOn.value) {
getDefaultStartEndDate(getCurrentLocale(), false)
} else {
if (nextDisabledDateIndex >= 0) {
disabledDates[nextDisabledDateIndex]
} else {
getDefaultStartEndDate(getCurrentLocale(), false)
}
}
},
onDateCleared = { state ->
endDate = getDefaultStartEndDate(state.data.locale, false)
},
onNegativeButtonClicked = { state ->
endDate = getDefaultStartEndDate(state.data.locale, false)
},
onPositiveButtonClicked = { state ->
endDate = getDefaultStartEndDate(state.data.locale, false)
},
onCancel = { state ->
endDate = getDefaultStartEndDate(state.data.locale, false)
}
)
/**
* An example of how to find the next disabled date after a selected date given an ordered list of
* disabled dates. This can be used to customize range selection behavior depending on the selected
* date.
*/
fun findNextDisabledDateIndex(date: Date, disabledDates: List<Date>): Int {
if (disabledDates.isNotEmpty()) {
val cal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
cal.time = date
var low = 0
var mid = 0
var high = disabledDates.size - 1
while (low <= high) {
mid = (low + high) / 2
if (cal.time.after(disabledDates[mid])) {
low = mid + 1
} else if (cal.time.before(disabledDates[mid])) {
high = mid - 1
} else {
return mid
}
}
return if (cal.time.before(disabledDates[mid])) {
mid
} else {
if (mid + 1 < disabledDates.size) {
mid + 1
} else {
-1
}
}
} else {
return -1
}
}
Custom Range Selection Behavior (Reset Range If Disabled Date Is Crossed)¶
This code snippet demonstrates how to create a Date Picker with customized behavior for range
selection. The Date Picker will reset the selected date range if the user tries to select a
date range that crosses a disabled date. The end date that is past the disabled date will be
considered the start date of a new range selection. The code utilizes the selectedRangeStartDate
and selectedRangeEndDate properties of the FioriDatePickerState object to achieve this
behavior.
// getDefaultStartEndDate() implementation can be found in the Util.kt file for Fiori Calendar
var endDate by rememberSaveable { mutableStateOf(getDefaultStartEndDate(getCurrentLocale(), false)) }
val disabledDates = ArrayList<Date>()
val cal = getCalendar(getCurrentLocale())
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 3)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 10)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 15)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 21)
disabledDates.add(cal.time)
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 27)
disabledDates.add(cal.time)
val isDateDisabled: (Date) -> Boolean = {
var isDisabled = false
// getCalendar() implementation can be found in the Util.kt file for Fiori Calendar
val currentCal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
currentCal.time = it
val disabledCal = getCalendar(getCurrentLocale(), CalendarType.GREGORIAN)
for (date in disabledDates) {
disabledCal.time = date
// isSameDate() implementation can be found in the Util.kt file for Fiori Calendar
if (isSameDate(currentCal, disabledCal)) {
isDisabled = true
}
}
isDisabled || it > endDate
}
DatePicker(
state = FioriDatePickerState(
FioriCalendarData(
endDate = endDate,
useRangeSelection = true,
isDateDisabled = isDateDisabled
)
),
rangeSupportText = "Range will reset if it crosses a disabled date",
useRange = true,
onDateClicked = { date, state, calendarState ->
if (state.rangePickOn.value) {
val currCal = getCalendar(calendarState.locale)
currCal.time = state.selectedRangeStartDate.value
while (currCal.time.before(state.selectedRangeEndDate.value)) {
if (isDateDisabled(currCal.time)) {
fioriCalendarUpdateSelectedDate(calendarState, date)
state.selectedRangeStartDate.value = date
state.selectedRangeEndDate.value = date
break
}
currCal.add(Calendar.DATE, 1)
}
}
}
)