본문 바로가기
Flutter + Dart/Flutter + Dart 공부

flutter 달력 추가하기

by GREEN나무 2025. 5. 15.
728x90

 

1. 기본 준비

✅ 필요한 패키지

패키지 설명
table_calendar Flutter에서 다양한 달력 UI와 기능을 제공
intl 날짜 및 시간 포맷 (예: yyyy-MM-dd → 2024년 05월 15일 등)

✅ 설치 명령어 (터미널에 입력)

flutter pub add table_calendar
flutter pub add intl

 

pubspec.yaml

 dependencies:
  table_calendar: ^3.0.9 # 달력
  intl: ^0.18.1 # DateFormat 사용을 위해 추가

  • 달력 만들기 단계:
      1. 달력의 기본 틀(컨테이너, 격자 등) 설정
      2. 날짜 표시를 위한 속성 지정
      3. 사용자 인터랙션 위해 속성이나 명령어 추가
    • 주의할 점:
      • 날짜와 월/년 변경은 별도 속성 또는 명령어 사용
      • 보기 쉽게 만들기 위해 스타일도 고려

2. 핵심 속성 정리 (table_calendar 기준)

구분 속성명 설명
날짜 범위 firstDay / lastDay 선택 가능한 최소/최대 날짜 설정
현재 포커스 날짜 focusedDay 현재 달력을 표시할 기준 날짜
언어 설정 locale 달력의 언어 설정 (ko-KR 등)
날짜 선택 onDaySelected 날짜를 선택했을 때 실행되는 콜백
선택 조건 selectedDayPredicate 선택된 날짜 여부를 판단
스타일 설정 headerStyle / calendarStyle 달력 헤더, 셀 스타일 지정
이벤트 표시 eventLoader 날짜별 이벤트 점 등을 표시
커스터마이징 calendarBuilders 달력의 특정 부분을 위젯으로 재구성 가능

+

구분 이름 또는 설명 예시 또는 상세 설명
속성 (Attributes)    
year 연도를 지정 year=2025
month 월을 지정 month=5
day 특정 날짜 지정 day=15
startDay 주의 시작 요일 (일, 월, 화, 등) startDay=Monday
showWeekNum 주 번호 표시 여부 showWeekNum=true
viewMode 달력 시작 모드 (월별, 연별 등) viewMode=month
highlightToday 오늘 날짜 강조 highlightToday=true
명령어 / 함수    
goToMonth() 특정 월로 이동하는 함수 goToMonth(6) (6월로 이동)
goToYear() 특정 연도로 이동하는 함수 goToYear(2026)
nextMonth() 다음 달로 이동 nextMonth()
prevMonth() 이전 달로 이동 prevMonth()
refresh() 달력을 새로고침 또는 갱신 refresh()
위젯/컴포넌트    
Calendar 달력 전체를 감싸는 위젯 <Calendar />
Header 년월, 조작 버튼(이전/다음) 포함 <Header />
DayGrid 날짜를 격자 형태로 보여주는 부분 <DayGrid />
WeekNumber 주 번호를 보여주는 기능 <WeekNumber />
DateCell 개별 날짜 표시 셀 <DateCell />

 

날짜 관련

날짜 지정
시작날짜를 
firstDay: DateTime(2025, 1, 1),
firstDay:  DateTime.now().subtract( const Duration(days: 365 * 10));
lastDay: DateTime.now().add( const Duration(days: 365 * 10));

DateTime.now()    지금 일자
.subtract 빼기
.add 더하기

 

구분 항목 설명 / 기능 예시 / 참고
기본 날짜/시간 자료구조 DateTime 날짜와 시간 표현, 생성, 조작 DateTime.now(), DateTime(2024, 5, 15, 14, 30)
  Duration 시간 차이 표현, 더하기/빼기 Duration(days: 3), Duration(hours: 2)
날짜/시간 생성 및 읽기 DateTime.now() 현재 날짜/시간 가져오기 print(DateTime.now())
  DateTime.utc() UTC 기준 날짜/시간 생성 DateTime.utc(2024, 5, 15)
  date.year, date.month 연, 월, 일 정보 읽기 date.year
  date.day, date.hour, date.minute 일, 시, 분 정보 읽기 date.day
날짜/시간 포맷 intl 패키지의 DateFormat 날짜 문자열 포맷팅 DateFormat('yyyy-MM-dd').format(date)
날짜 연산 date.add(Duration(days: 5)) 날짜 더하기 date.subtract(Duration(days: 3))
  date.isBefore(), date.isAfter() 날짜 비교 date1.isBefore(date2)
날짜 차이 계산 (date2.difference(date1)).inDays 두 날짜 차이 일수 계산 DateTime.now().difference(otherDate).inDays
시간 포맷팅 intl 패키지의 DateFormat 문자열로 시간 포맷팅 DateFormat('HH:mm').format(date)
시간 계산 Duration 활용 시간 더하기/빼기 duration = Duration(hours: 1); date.add(duration)
힙합/캘린더 위젯 table_calendar 패키지 Flutter 달력 위젯 제공 TableCalendar()
  CalendarDatePicker Flutter 내장 날짜 선택 위젯 CalendarDatePicker()
  CupertinoDatePicker iOS 스타일 날짜/시간 선택기 CupertinoDatePicker()
달력 속성 focusedDay 현재 보여지는 날짜 중심 focusedDay: DateTime.now()
  selectedDayPredicate 선택된 날짜 표시 조건 (day) => isSameDay(selectedDay, day)
  firstDay, lastDay 선택 가능한 날짜 범위 firstDay: DateTime(2000), lastDay: DateTime(2100)
  weekDayStyle, headerStyle 달력 스타일 커스터마이징 headerStyle: HeaderStyle()
달력 이벤트 및 표시 Event 클래스, 이벤트 리스트 특정 날짜에 이벤트 연결 Map<DateTime, List<Event>>
  valueNotifier 선택된 날짜/이벤트 상태 저장 ValueNotifier<List<Event>>
기타 유용 함수 및 속성 isSameDay() 두 날짜가 같은지 비교 isSameDay(date1, date2)
  format() 날짜를 문자열로 포맷팅 DateFormat('yyyy-MM-dd').format(date)
       
  toLocal(), toUtc() 시간대 변환 date.toUtc(), date.toLocal()

3. 예시 코드 (간단한 달력 만들기)

.dart

더보기
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';

class CalendarPage extends StatefulWidget {
  @override
  _CalendarPageState createState() => _CalendarPageState();
}

class _CalendarPageState extends State<CalendarPage> {
  late final ValueNotifier<List<Event>> _selectedEvents;
  CalendarFormat _calendarFormat = CalendarFormat.month;
  DateTime _focusedDay = DateTime.now();
  DateTime? _selectedDay;

  @override
  void initState() {
    super.initState();

    _selectedDay = _focusedDay;
    _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
  }

  @override
  void dispose() {
    _selectedEvents.dispose();
    super.dispose();
  }

  List<Event> _getEventsForDay(DateTime day) {
    // 이벤트 데이터를 가져오는 로직 또는 테스트용 더미 데이터
    return kEvents[day] ?? [];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 전체 깔끔한 배경 없이 달력만 보여주는 구조
      body: Column(
        children: [
          TableCalendar<Event>(
            firstDay: DateTime.utc(2000, 1, 1),
            lastDay: DateTime.utc(2100, 12, 31),
            focusedDay: _focusedDay,
            calendarFormat: _calendarFormat,
            selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
            onDaySelected: (selectedDay, focusedDay) {
              setState(() {
                _selectedDay = selectedDay;
                _focusedDay = focusedDay; // 뷰 포커스 이동
                _selectedEvents.value = _getEventsForDay(selectedDay);
              });
            },
            onFormatChanged: (format) {
              setState(() {
                _calendarFormat = format;
              });
            },
            onPageChanged: (focusedDay) {
              _focusedDay = focusedDay;
            },
            // 달력 스타일 커스터마이즈 가능
            calendarStyle: CalendarStyle(
              todayDecoration: BoxDecoration(
                color: Colors.blueAccent,
                shape: BoxShape.circle,
              ),
              selectedDecoration: BoxDecoration(
                color: Colors.orange,
                shape: BoxShape.circle,
              ),
            ),
            // 헤더 스타일 커스터마이즈
            headerStyle: HeaderStyle(
              formatButtonVisible: false,
              titleCentered: true,
            ),
          ),
        ],
      ),
    );
  }
}

// 이벤트 데이터 구조
class Event {
  final String title;

  const Event(this.title);

  @override
  String toString() => title;
}

// 더미 이벤트 데이터
final Map<DateTime, List<Event>> kEvents = {
  DateTime.utc(2025, 5, 15): [Event('이벤트 1')],
  DateTime.utc(2025, 5, 20): [Event('이벤트 2')],
  DateTime.utc(2025, 6, 10): [Event('이벤트 3')],
};

4. 코드 해설

  • StatefulWidget: 날짜 선택 등 상태 변화가 있는 UI 구성
  • TableCalendar: 실제 달력을 구성하는 핵심 위젯
  • onDaySelected: 날짜 선택 시 동작 정의 (setState()로 상태 갱신)
  • selectedDayPredicate: 선택된 날짜를 강조 표시
  • intl: 선택한 날짜를 보기 좋게 포맷
  • DateTime.utc()는 UTC 시간(전 세계 표준시) 기준으로 생성됩니다.
  • DateTime()은 기기 또는 시스템의 로컬 타임존 기준으로 생성됩니다.

 


참고

https://dongkyu.tistory.com/43