2024. 12. 17. 07:58ㆍ같이 공부합시다 - Flutter/Flutter로 To-Do 앱 만들기
저번 시간에는 캘린더 패키지를 이용해서 띄우기까지 성공했습니다.
자, 이번 시간에는 Flutter를 사용해 To-Do 리스트 앱에 캘린더 기능을 한층 더 살려봅시다.

할 일 리스트에 날짜 정보 추가하기
캘린더와 연동하려면 할 일 리스트에도 날짜 정보가 포함되어야 합니다.
<할 일 리스트 확장>
final List<Map<String, dynamic>> _todoList = [
{'task': '할 일 1', 'isCompleted': false, 'date': '2024-12-13'},
{'task': '할 일 2', 'isCompleted': true, 'date': '2024-12-13'},
];
이런식으로 말이죠.
날짜별 이벤트 저장
날짜별로도 할 일을 빠르게 조회하기 위해
Map<DateTime, List<String>> 형태로 저장합니다.
Map 은 키-값 쌍으로 데이터를 저장하는 컬렉션입니다.
여기에서의 키는 날짜(DateTime) 이며,
날짜에 따른 할 일 목록(List<String>) 이 됩니다.
할 일 목록은 하나가 아니기 때문에,
List<String> 으로 여러 정보를 담습니다.
<날짜별 이벤트 저장 변수를 만들었다.>
final Map<DateTime, List<String>> _calendarEvents = {};
<날짜별 이벤트 저장은 여기에>

추가로 캘린더에서 쓰일 _focusedDay 와 _selectedDay 도 같이 만들어 둡니다.
_focusedDay 는 오늘 날짜이고, _selectedDay 는 사용자가 날짜를 선택했을 때 선택한 날짜를 저장하도록 할 겁니다.
호출부와 처리 메서드 연동
캘린더 UI 호출
앱에서 캘린더를 표시할 위치를 정하고, UI를 호출하는 메서드를 작성합니다.
앱 상단의 캘린더 아이콘을 누르면 캘린더를 호출하도록 설정합니다.
void _showCalendar() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return Column(
children: [
TableCalendar(
focusedDay: _focusedDay,
firstDay: DateTime(2000),
lastDay: DateTime(2100),
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
Navigator.of(context).pop(); // 캘린더 닫기
},
),
const SizedBox(height: 16),
Expanded(
child: ListView(
children: _getEventsForDay(_selectedDay ?? _focusedDay)
.map((event) => ListTile(
title: Text(event),
))
.toList(),
),
),
],
);
},
);
}
이 코드는 Flutter에서 TableCalendar 위젯을 사용하여 캘린더를 표시하고, 선택된 날짜와 관련된 이벤트 목록을 함께 보여주는 기능을 구현한 것입니다. 캘린더는 showModalBottomSheet를 통해 하단 모달로 표시됩니다.
코드 상세 분석
🔸showModalBottomSheet
- Flutter에서 하단 모달 화면을 표시하는 위젯입니다.
- 사용자 정의 UI를 추가할 수 있고, 하단에서 화면 일부를 덮어쓰는 스타일로 표시됩니다.
매개변수
- context: 현재 위젯 트리의 빌드 컨텍스트를 전달합니다.
- isScrollControlled: true:
- 모달 높이를 사용자가 추가하는 콘텐츠에 맞게 조절하도록 설정합니다.
<showModalBottomSheet 위젯 isScrollControlled 속성에 따른 UI 차이>

- builder: 모달에 표시할 UI를 빌드하는 함수입니다.
🔸 Column
모달 내에서 캘린더와 이벤트 목록을 세로로 배치하기 위해 사용됩니다.
Column 구성 요소
- TableCalendar:
- Flutter 패키지에서 제공하는 캘린더 위젯입니다.
- 달력과 날짜를 선택할 수 있는 기능을 제공합니다.
- 주요 속성과 동작:
- focusedDay: 캘린더가 현재 표시할 날짜를 지정합니다.
- firstDay / lastDay: 캘린더에서 선택 가능한 날짜의 범위를 설정합니다.
- selectedDayPredicate: 특정 날짜가 선택되었는지 여부를 정의하는 콜백 함수입니다.
- onDaySelected: 날짜를 선택했을 때 호출되는 콜백 함수입니다.
- 선택된 날짜(selectedDay)와 포커스된 날짜(focusedDay)를 업데이트합니다.
- Navigator.of(context).pop()을 호출하여 모달을 닫습니다.
- const SizedBox(height: 16):
- 캘린더와 이벤트 목록 사이에 16픽셀의 간격을 만듭니다.
- Expanded:
- 이벤트 목록을 캘린더 아래에서 남은 공간을 채우며 확장되도록 설정합니다.
- ListView:
- 선택된 날짜의 이벤트를 스크롤 가능한 리스트로 표시합니다.
- _getEventsForDay() 함수가 반환하는 이벤트 목록을 기반으로 ListTile을 생성합니다.
할 일 추가와 캘린더 데이터 연동
할 일을 추가할 때 날짜 정보를 저장하고, calendarEvents에 추가합니다.
void _addTodoItem(String task) {
final today = DateTime.now();
final dateKey = DateTime(today.year, today.month, today.day);
setState(() {
_todoList.add({'task': task, 'isCompleted': false, 'date': today.toIso8601String()});
_calendarEvents[dateKey] = _calendarEvents[dateKey] ?? [];
_calendarEvents[dateKey]!.add(task);
});
}
today.toIso8601String() 메서드는 ISO 8601 표준 형식의 문자열로 날짜와 시간을 반환합니다.
이 형식은 국제적으로 널리 사용되며, 데이터 전송 및 저장에 유용합니다.
데이터 예시
final today = DateTime.now();
print(today.toIso8601String());
출력 예시
2024-12-16T14:30:15.123
형식 설명
- 2024-12-16: 날짜 (년-월-일)
- 2024: 연도
- 12: 월 (12월)
- 16: 일 (16일)
- T: 날짜와 시간 구분자
- 14:30:15.123: 시간 (시:분:초.밀리초)
- 14: 24시간 형식의 시 (오후 2시)
- 30: 분
- 15: 초
- .123: 밀리초
날짜별 데이터 조회 메서드
선택된 날짜나 현재 포커스된 날짜에 해당하는 이벤트 목록을 반환하는 역할을 합니다.
이 함수는 캘린더와 이벤트 목록을 연동하는 데 중요한 역할을 합니다.
List<String> _getEventsForDay(DateTime day) {
final dateKey = DateTime(day.year, day.month, day.day);
return _calendarEvents[dateKey] ?? [];
}
- 특정 날짜에 대한 이벤트 조회:
- _selectedDay 또는 _focusedDay를 기준으로, 해당 날짜와 관련된 이벤트를 가져옵니다.
- 리턴값:
- 해당 날짜에 관련된 이벤트들을 List<String> 형태로 반환합니다.
코드 상세 분석
1. 이벤트 데이터 구조
- _calendarEvents는 날짜별 이벤트를 저장하는 Map<DateTime, List<String>> 형태입니다.
- Key: DateTime – 날짜
- Value: List<String> – 해당 날짜의 이벤트 목록
- 이 구조를 통해 날짜별로 이벤트를 쉽게 조회할 수 있습니다.
예시 데이터
{
DateTime(2024, 12, 10): ['회의 참석', 'Flutter 강의 듣기'],
DateTime(2024, 12, 11): ['운동하기', '친구와 저녁 식사']
}
2. 날짜에 대한 이벤트 조회
_calendarEvents[dateKey] ?? [];
- _calendarEvents[dateKey]:
- dateKey 에 해당하는 날짜의 이벤트를 가져옵니다.
- 해당 날짜가 없으면 null을 반환합니다.
- ?? []:
- null일 경우 빈 리스트([])를 반환합니다.
- 이를 통해 특정 날짜에 이벤트가 없을 때도 에러 없이 처리됩니다.
_getEventsForDay가 반환된 데이터 활용
이 함수는 반환된 이벤트 데이터를 리스트 형태로 UI에 연결하는 데 사용됩니다.
사용 예시
Expanded(
child: ListView(
children: _getEventsForDay(_selectedDay ?? _focusedDay)
.map((event) => ListTile(
title: Text(event),
))
.toList(),
),
),
코드 설명
- _getEventsForDay(_selectedDay ?? _focusedDay):
- 선택된 날짜(_selectedDay)가 있으면 해당 날짜의 이벤트를 가져옵니다.
- 없으면 현재 포커스된 날짜(_focusedDay)를 기준으로 이벤트를 가져옵니다.
- 예: ['회의 참석', 'Flutter 강의 듣기']
- .map((event) => ListTile(...)):
- 반환된 이벤트 리스트를 순회하면서, 각 이벤트를 ListTile로 변환합니다.
- 예: '회의 참석' → ListTile(title: Text('회의 참석'))
- .toList():
- Iterable 형태의 데이터를 List로 변환하여 UI에서 사용할 수 있도록 합니다.
캘린더 디자인 개선
- 날짜 아래에 간단한 이벤트 마커를 표시하도록 TableCalendar의 CalendarBuilders를 활용합니다.
calendarBuilders: CalendarBuilders(
markerBuilder: (context, day, events) {
final eventList = _getEventsForDay(day);
if (eventList.isNotEmpty) {
return Positioned(
bottom: 1,
child: Container(
width: 8.0,
height: 8.0,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
);
}
return null;
},
),
날짜별 상세 보기
캘린더에서 특정 날짜를 클릭했을 때 선택된 날짜의 할 일을 메인 화면에 표시하도록 설정합니다.
void _showTasksForSelectedDay() {
final selectedDateTasks = _getEventsForDay(_selectedDay ?? DateTime.now());
showModalBottomSheet(
context: context,
builder: (context) {
return ListView(
children: selectedDateTasks
.map((task) => ListTile(
title: Text(task),
))
.toList(),
);
},
);
}
전체 흐름 요약
- UI 설계
- 캘린더 UI: TableCalendar로 구현.
- 선택된 날짜 아래에 할 일 표시.
- 데이터 설계
- 날짜별로 할 일을 저장하는 데이터 구조 확장.
- Map<DateTime, List<String>>로 데이터 저장.
- 메서드 연동
- 캘린더 호출, 할 일 추가 시 날짜 정보 연동.
- 선택된 날짜의 할 일을 표시.
- 점진적 개선
- 디자인 개선: 날짜 아래 마커 표시.
- 선택된 날짜의 상세 보기 기능 추가.
원했던 캘린더 기능이 어느정도 완성되었네요.
오늘도 고생하셨습니다 !
끝 !
깃허브 : todo_app/lib/main.dart at main · SteadyBuilder/todo_app
'같이 공부합시다 - Flutter > Flutter로 To-Do 앱 만들기' 카테고리의 다른 글
Flutter로 To-Do 리스트 앱 개선하기: 캘린더 닫기 버튼 추가하기 (129) | 2024.12.20 |
---|---|
Flutter UI 개선: TableCalendar에 2주 보기 옵션 넣는 방법 (0) | 2024.12.18 |
Flutter로 To-Do 리스트 앱에 캘린더 기능 추가하기 (TableCalendar 활용) (1) (0) | 2024.12.16 |
최신 JDK LTS 버전 설치 (버전 업그레이드) + Gradle 버전 업그레이드 (1) | 2024.12.12 |
flutter build apk 오류 해결 (네트워크 방화벽에 막혔을 때) (7) | 2024.12.12 |