날짜 선택 도구를 사용하면 사용자가 날짜, 기간 또는 둘 다 선택할 수 있습니다. 사용자가 날짜를 선택할 수 있도록 캘린더 대화상자나 텍스트 입력을 사용합니다.
유형
날짜 선택기에는 세 가지 유형이 있습니다.
- 도킹됨: 레이아웃 내에 인라인으로 표시됩니다. 전용 대화상자가 거슬릴 수 있는 컴팩트 레이아웃에 적합합니다.
- 모달: 앱 콘텐츠를 오버레이하는 대화상자로 표시됩니다. 이렇게 하면 날짜 선택에 명확하게 집중할 수 있습니다.
- 모달 입력: 텍스트 필드와 모달 날짜 선택기를 결합합니다.
다음 컴포저블을 사용하여 앱에서 이러한 날짜 선택기를 구현할 수 있습니다.
DatePicker
: 날짜 선택기의 일반 컴포저블입니다. 사용하는 컨테이너에 따라 도크인지 모델인지가 결정됩니다.DatePickerDialog
: 모달과 모달 입력 날짜 선택기를 모두 포함하는 컨테이너입니다.DateRangePicker
: 시작일과 종료일이 있는 범위를 사용자가 선택할 수 있는 모든 날짜 선택기
상태
다양한 날짜 선택기 컴포저블이 공통으로 공유하는 키 매개변수는 state
이며, DatePickerState
또는 DateRangePickerState
객체를 사용합니다. 이러한 속성은 현재 선택된 날짜와 같이 날짜 선택 도구를 사용한 사용자의 선택에 관한 정보를 캡처합니다.
선택한 날짜를 사용하는 방법에 대한 자세한 내용은 선택한 날짜 사용 섹션을 참고하세요.
도킹된 날짜 선택 도구
다음 예에서는 사용자에게 생년월일을 입력하라는 텍스트 필드가 있습니다. 필드의 캘린더 아이콘을 클릭하면 입력 필드 아래에 도킹된 날짜 선택기가 열립니다.
@Composable fun DatePickerDocked() { var showDatePicker by remember { mutableStateOf(false) } val datePickerState = rememberDatePickerState() val selectedDate = datePickerState.selectedDateMillis?.let { convertMillisToDate(it) } ?: "" Box( modifier = Modifier.fillMaxWidth() ) { OutlinedTextField( value = selectedDate, onValueChange = { }, label = { Text("DOB") }, readOnly = true, trailingIcon = { IconButton(onClick = { showDatePicker = !showDatePicker }) { Icon( imageVector = Icons.Default.DateRange, contentDescription = "Select date" ) } }, modifier = Modifier .fillMaxWidth() .height(64.dp) ) if (showDatePicker) { Popup( onDismissRequest = { showDatePicker = false }, alignment = Alignment.TopStart ) { Box( modifier = Modifier .fillMaxWidth() .offset(y = 64.dp) .shadow(elevation = 4.dp) .background(MaterialTheme.colorScheme.surface) .padding(16.dp) ) { DatePicker( state = datePickerState, showModeToggle = false ) } } } } } @Composable fun DatePickerFieldToModal(modifier: Modifier = Modifier) { var selectedDate by remember { mutableStateOf<Long?>(null) } var showModal by remember { mutableStateOf(false) } OutlinedTextField( value = selectedDate?.let { convertMillisToDate(it) } ?: "", onValueChange = { }, label = { Text("DOB") }, placeholder = { Text("MM/DD/YYYY") }, trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = "Select date") }, modifier = modifier .fillMaxWidth() .pointerInput(selectedDate) { awaitEachGesture { // Modifier.clickable doesn't work for text fields, so we use Modifier.pointerInput // in the Initial pass to observe events before the text field consumes them // in the Main pass. awaitFirstDown(pass = PointerEventPass.Initial) val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial) if (upEvent != null) { showModal = true } } } ) if (showModal) { DatePickerModal( onDateSelected = { selectedDate = it }, onDismiss = { showModal = false } ) } } fun convertMillisToDate(millis: Long): String { val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()) return formatter.format(Date(millis)) }
코드에 관한 핵심 사항
- 사용자가
IconButton
를 클릭하면 날짜 선택기가 표시됩니다.- 아이콘 버튼은
OutlinedTextField
의trailingIcon
매개변수의 인수로 사용됩니다. showDatePicker
상태 변수는 도킹된 날짜 선택 도구의 공개 상태를 제어합니다.
- 아이콘 버튼은
- 날짜 선택기의 컨테이너는
Popup
컴포저블로, 다른 요소의 레이아웃에 영향을 주지 않고 콘텐츠를 오버레이합니다. selectedDate
는DatePickerState
객체에서 선택한 날짜의 값을 캡처하고convertMillisToDate
함수를 사용하여 형식을 지정합니다.- 선택한 날짜가 텍스트 필드에 표시됩니다.
- 도킹된 날짜 선택기는
offset
수정자를 사용하여 텍스트 필드 아래에 배치됩니다. Box
는 텍스트 필드와 날짜 선택기의 적절한 레이어링을 허용하는 루트 컨테이너로 사용됩니다.
결과
캘린더 아이콘을 클릭하면 이 구현이 다음과 같이 표시됩니다.

모달 날짜 선택기
모달 날짜 선택 도구는 화면 위에 떠 있는 대화상자를 표시합니다. 이를 구현하려면 DatePickerDialog
를 만들고 DatePicker
를 전달합니다.
@Composable fun DatePickerModal( onDateSelected: (Long?) -> Unit, onDismiss: () -> Unit ) { val datePickerState = rememberDatePickerState() DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton(onClick = { onDateSelected(datePickerState.selectedDateMillis) onDismiss() }) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DatePicker(state = datePickerState) } }
코드에 관한 핵심 사항
DatePickerModal
컴포저블 함수는 모달 날짜 선택 도구를 표시합니다.- 사용자가 날짜를 선택하면
onDateSelected
람다 표현식이 실행됩니다.- 선택한 날짜를 상위 컴포저블에 노출합니다.
- 사용자가 대화상자를 닫으면
onDismiss
람다 표현식이 실행됩니다.
결과
이 구현은 다음과 같이 표시됩니다.

입력 모달 날짜 선택기
입력이 있는 모달 날짜 선택기는 화면 위로 떠다니는 대화상자를 표시하고 사용자가 날짜를 입력할 수 있도록 합니다.
@Composable fun DatePickerModalInput( onDateSelected: (Long?) -> Unit, onDismiss: () -> Unit ) { val datePickerState = rememberDatePickerState(initialDisplayMode = DisplayMode.Input) DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton(onClick = { onDateSelected(datePickerState.selectedDateMillis) onDismiss() }) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DatePicker(state = datePickerState) } }
코드에 관한 핵심 사항
이는 모달 날짜 선택기 예시와 매우 유사합니다. 주요 차이점은 다음과 같습니다.
initialDisplayMode
매개변수는 초기 표시 모드를DisplayMode.Input
로 설정합니다.

범위가 있는 날짜 선택기
사용자가 시작일과 종료일 사이의 범위를 선택할 수 있는 날짜 선택 도구를 만들 수 있습니다. 이렇게 하려면 DateRangePicker
를 사용합니다.
DateRangePicker
사용은 기본적으로 DatePicker
과 동일합니다. PopUp
의 하위 요소로 도킹된 선택기에 사용할 수도 있고 모달 선택기로 사용하여 DatePickerDialog
에 전달할 수도 있습니다. 주요 차이점은 DatePickerState
대신 DateRangePickerState
를 사용한다는 것입니다.
다음 스니펫은 범위가 있는 모달 날짜 선택기를 만드는 방법을 보여줍니다.
@Composable fun DateRangePickerModal( onDateRangeSelected: (Pair<Long?, Long?>) -> Unit, onDismiss: () -> Unit ) { val dateRangePickerState = rememberDateRangePickerState() DatePickerDialog( onDismissRequest = onDismiss, confirmButton = { TextButton( onClick = { onDateRangeSelected( Pair( dateRangePickerState.selectedStartDateMillis, dateRangePickerState.selectedEndDateMillis ) ) onDismiss() } ) { Text("OK") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) { DateRangePicker( state = dateRangePickerState, title = { Text( text = "Select date range" ) }, showModeToggle = false, modifier = Modifier .fillMaxWidth() .height(500.dp) .padding(16.dp) ) } }
코드에 관한 핵심 사항
onDateRangeSelected
매개변수는 선택한 시작일과 종료일을 나타내는Pair<Long?, Long?>
를 수신하는 콜백입니다. 이렇게 하면 상위 컴포저블이 선택된 범위에 액세스할 수 있습니다.rememberDateRangePickerState()
는 날짜 범위 선택기의 상태를 만듭니다.DatePickerDialog
는 모달 대화상자 컨테이너를 만듭니다.- 확인 버튼의
onClick
핸들러에서onDateRangeSelected
는 선택한 범위를 상위 컴포저블에 전달합니다. DateRangePicker
컴포저블은 대화상자 콘텐츠 역할을 합니다.
결과
이 구현은 다음과 같이 표시됩니다.

선택한 날짜 사용
선택한 날짜를 캡처하려면 상위 컴포저블에서 Long
로 추적하고 onDateSelected
의 DatePicker
에 값을 전달합니다. 다음 스니펫은 이를 보여주지만 공식 스니펫 앱에서 전체 구현을 확인할 수 있습니다.
// ... var selectedDate by remember { mutableStateOf<Long?>(null) } // ... if (selectedDate != null) { val date = Date(selectedDate!!) val formattedDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(date) Text("Selected date: $formattedDate") } else { Text("No date selected") } // ... DatePickerModal( onDateSelected = { selectedDate = it showModal = false }, onDismiss = { showModal = false } ) } // ...
시작 값과 종료 값을 캡처하려면 Pair<Long?, Long?>
또는 데이터 클래스를 사용해야 하지만 범위 날짜 선택기에도 기본적으로 동일하게 적용됩니다.