Flutter 앱에서 사용되는 showDatePicker 의 효과적인 사용방법에 대해 이야기해보려고 합니다.
아래 위젯은 사용자가 일간, 주간, 월간 데이터를 쉽게 탐색할 수 있게 해주는 중요한 UI 요소입니다.
DateSelector 위젯 소개
DateSelector는 다음과 같은 주요 기능을 제공합니다:
- 현재 선택된 날짜 표시
- 날짜 증가/감소 버튼
- 달력을 통한 날짜 선택
- 일간/주간/월간 모드 지원
이제 각 부분을 자세히 살펴보겠습니다.
주요 구성 요소
1. 상태 관리
class _DateSelectorState extends State<DateSelector> { late DateTime _selectedDate; late dynamic _periodType; @override void initState() { super.initState(); _selectedDate = widget.selectedDate; _periodType = widget.periodType; } }
_selectedDate
와 _periodType
은 위젯의 핵심 상태입니다. initState()
에서 초기화됩니다.
2. 날짜 증가/감소 로직
void _incrementDate() { setState(() { final now = DateTime.now(); if (_periodType == 0 || _periodType == 'daily') { final newDate = _selectedDate.add(const Duration(days: 1)); if (newDate.isBefore(now.add(const Duration(days: 1)))) { _selectedDate = newDate; } } else if (_periodType == 1 || _periodType == 'weekly') { final currentWeekStart = _selectedDate.subtract(Duration(days: _selectedDate.weekday % 7)); final nextWeekStart = currentWeekStart.add(const Duration(days: 7)); if (nextWeekStart.isBefore(now)) { _selectedDate = nextWeekStart; } else { _selectedDate = now.subtract(Duration(days: now.weekday % 7)); } } else if (_periodType == 2 || _periodType == 'monthly') { final newDate = DateTime(_selectedDate.year, _selectedDate.month + 1, 1); if (newDate.isBefore(DateTime(now.year, now.month, now.day + 1))) { _selectedDate = newDate; } } widget.onDateChanged(_selectedDate); }); }
이 메서드는 선택된 날짜를 증가시킵니다. 주목할 점:
- 일간/주간/월간 모드에 따라 다르게 동작합니다.
- 현재 날짜를 넘어가지 않도록 체크합니다.
- 주간 모드에서는 일요일을 기준으로 주를 계산합니다.
3. 날짜 증가 가능 여부 확인
bool canIncrementDate() { final now = DateTime.now(); if (_periodType == 0 || _periodType == 'daily') { return _selectedDate.isBefore(now); } else if (_periodType == 1 || _periodType == 'weekly') { final currentWeekStart = _selectedDate.subtract(Duration(days: _selectedDate.weekday % 7)); final nextWeekStart = currentWeekStart.add(const Duration(days: 7)); return nextWeekStart.isBefore(now); } else if (_periodType == 2 || _periodType == 'monthly') { final nextMonth = DateTime(_selectedDate.year, _selectedDate.month + 1, 1); return nextMonth.isBefore(DateTime(now.year, now.month, 1)); } return false; }
이 메서드는 날짜를 더 증가시킬 수 있는지 확인합니다. UI에서 버튼의 활성화 여부를 결정하는 데 사용됩니다.
4. UI 구성
@override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: const Icon(FluentIcons.caret_left_24_filled), color: const Color(0xff9CA4AC), iconSize: 20, padding: EdgeInsets.zero, onPressed: _decrementDate, ), const SizedBox(width: 10), Text( FormatterUtil.formatSelectedDate(_selectedDate, _periodType), style: const TextStyle( fontFamily: 'Pretendard', fontSize: 15, color: Color(0xff9CA4AC), fontWeight: FontWeight.w500, letterSpacing: -0.2, ), ), IconButton( icon: const Icon(FluentIcons.calendar_24_regular), iconSize: 20, onPressed: () => _pickDate(context), ), IconButton( icon: const Icon(FluentIcons.caret_right_24_filled), iconSize: 20, onPressed: canIncrementDate() ? _incrementDate : null, color: canIncrementDate() ? const Color(0xff9CA4AC) : const Color(0xff818990), ), ], ); }
UI는 간단한 Row 위젯으로 구성됩니다:
- 왼쪽 화살표 (날짜 감소)
- 현재 선택된 날짜 텍스트
- 달력 아이콘 (날짜 직접 선택)
- 오른쪽 화살표 (날짜 증가)
주목할 점은 오른쪽 화살표의 onPressed
와 color
속성입니다. canIncrementDate()
의 결과에 따라 동적으로 설정됩니다.
결론
이 DateSelector 위젯은 다음과 같은 장점을 제공합니다:
- 직관적인 UI로 사용자가 쉽게 날짜를 탐색할 수 있습니다.
- 일간/주간/월간 모드를 지원하여 다양한 형태의 데이터 조회에 적합합니다.
- 현재 날짜를 넘어가지 않도록 하여 미래의 데이터 접근을 방지합니다.
- 동적인 UI 업데이트로 사용자에게 시각적 피드백을 제공합니다.