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 업데이트로 사용자에게 시각적 피드백을 제공합니다.