Implementing Material Design 3 Date Picker in Android Compose

Ken Ruiz Inoue
Deuk
Published in
4 min readMar 7, 2024

Objective

Implement Material Design 3 DatePickerDialog() & DatePicker() in an Android Compose app, to display the selected date as a formatted string.

Environment

  • Android Studio Iguana | 2023.2.1
  • Compose version: composeBom = "2023.08.00"
  • Pixel 6 API 30 Emulator
  • Project Minimum SDK: 27

Implementation

// Your package

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDefaults
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.DisplayMode
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale

@OptIn(ExperimentalMaterial3Api::class)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
// Initial state setup for the DatePickerDialog. Specifies to show the picker initially
val datePickerState = rememberDatePickerState(initialDisplayMode = DisplayMode.Picker)
// State to hold the selected date as a String
val selectedDateLabel = remember { mutableStateOf("") }
// State to control the visibility of the DatePickerDialog
val openDialog = remember { mutableStateOf(false) }
// Define the main color for the calendar picker
val calendarPickerMainColor = Color(0xFF722276)

// Layout for displaying the button and the selected date
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// Button to open the DatePickerDialog
Button(
onClick = {
openDialog.value = !openDialog.value
}
) {
Text("Open Date Picker")
}
// Displays the selected date
Text("Selected Date: ${selectedDateLabel.value}")
}

// Conditional display of the DatePickerDialog based on the openDialog state
if (openDialog.value) {
// DatePickerDialog component with custom colors and button behaviors
DatePickerDialog(
colors = DatePickerDefaults.colors(
containerColor = Color(0xFFF5F0FF),
),
onDismissRequest = {
// Action when the dialog is dismissed without selecting a date
openDialog.value = false
},
confirmButton = {
// Confirm button with custom action and styling
TextButton(
onClick = {
// Action to set the selected date and close the dialog
openDialog.value = false
selectedDateLabel.value =
datePickerState.selectedDateMillis?.convertMillisToDate() ?: ""
}
) {
Text("OK", color = calendarPickerMainColor)
}
},
dismissButton = {
// Dismiss button to close the dialog without selecting a date
TextButton(
onClick = {
openDialog.value = false
}
) {
Text("CANCEL", color = calendarPickerMainColor)
}
}
) {
// The actual DatePicker component within the dialog
DatePicker(
state = datePickerState,
colors = DatePickerDefaults.colors(
selectedDayContainerColor = calendarPickerMainColor,
selectedDayContentColor = Color.White,
selectedYearContainerColor = calendarPickerMainColor,
selectedYearContentColor = Color.White,
todayContentColor = calendarPickerMainColor,
todayDateBorderColor = calendarPickerMainColor
)
)
}
}
}
}
}

fun Long.convertMillisToDate(): String {
// Create a calendar instance in the default time zone
val calendar = Calendar.getInstance().apply {
timeInMillis = this@convertMillisToDate
// Adjust for the time zone offset to get the correct local date
val zoneOffset = get(Calendar.ZONE_OFFSET)
val dstOffset = get(Calendar.DST_OFFSET)
add(Calendar.MILLISECOND, -(zoneOffset + dstOffset))
}
// Format the calendar time in the specified format
val sdf = SimpleDateFormat("MMM dd, yyyy", Locale.US)
return sdf.format(calendar.time)
}

Result

More Resources

For developers eager to deepen their understanding or explore more about modern Android development, a wealth of resources and guides await.

Your thoughts and involvement are truly priceless. If you’ve found this guide helpful, I’d love to hear from you. Consider sharing your support through claps or a follow, and stay tuned for more insights into the evolving landscape of Android development. See you in the next tutorial!

Deuk Services: Your Gateway to Leading Android Innovation

Are you looking to boost your business with top-tier Android solutions?Partner with Deuk services and take your projects to unparalleled heights.

🚀 Boost Your Productivity with Notion

New to Notion? Discover how it can revolutionize your productivity

Ready to take your productivity to the next level? Integrate this content into your Notion workspace with ease:

1 Access the Notion Version of this Content

2 Look for the Duplicate button at the top-right corner of the page

3 Click on it to add this valuable resource to your Notion workspace

Seamlessly integrate this guide into your Notion workspace for easy access and swift reference. Leverage Notion AI to search and extract crucial insights, enhancing your productivity. Start curating your knowledge hub with Notion AI today and maximize every learning moment.

--

--