본문 바로가기
Flutter + Dart/다이어리 프로젝트

달력, 로컬 설정

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

Flutter 달력 만들기 & 트러블슈팅 가이드


1. Flutter 달력 기본 구현법

1-1. TableCalendar 패키지 설치

pubspec.yaml에 다음 의존성을 추가 후 flutter pub get 실행

dependencies:
  flutter:
    sdk: flutter
  table_calendar: ^3.0.9
  intl: ^0.18.1

1-2. 기본 달력 위젯 사용법

import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:intl/date_symbol_data_local.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initializeDateFormatting('ko_KR', null); // 필수 로케일 초기화
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('달력 예제')),
        body: TableCalendar(
          locale: 'ko_KR',
          firstDay: DateTime.utc(2000, 1, 1),
          lastDay: DateTime.utc(2100, 12, 31),
          focusedDay: DateTime.now(),
        ),
      ),
    );
  }
}
  • initializeDateFormatting() 호출은 한글 등 특정 로케일의 날짜/시간 포맷을 사용하기 위해 필수
  • locale: 'ko_KR' 로 설정해야 한글 달력이 나온다

2. 주요 트러블슈팅

2-1. 오류: Locale data has not been initialized

  • 오류 메시지:
    Locale data has not been initialized, call initializeDateFormatting(<locale>).
  • 원인:
    intl 패키지의 날짜 포맷 데이터가 초기화되지 않음.
  • 해결법:
    main() 함수에서 비동기로 await initializeDateFormatting('ko_KR', null); 호출 후 runApp() 실행해야 함.

2-2. 렌더링 과부하(프레임 스킵 등) 문제

  • 발생 상황:
    달력 렌더링 시 프레임이 많이 스킵되거나 앱이 느려짐
  • 원인:
    불필요한 상태 업데이트, 복잡한 위젯 트리, 무거운 연산을 메인 스레드에서 처리
  • 해결법:
    • Stateful 위젯에서 상태 관리를 최소화
    • 필요할 때만 빌드 호출
    • ListView, Calendar 같은 위젯은 캐싱, 메모리 절약에 신경쓰기
    • 화면 전환 등 복잡한 로직은 별도 isolate로 분리 검토

2-3. 권한 관련 오류

  • 위치 권한 등 시스템 권한이 없으면 위치 기반 기능이 동작 안 함
  • AndroidManifest.xml 등에서 ACCESS_FINE_LOCATION 권한 선언 필요

3. 달력과 일기 앱 예시 구조

  • 달력 표시: TableCalendar를 CalendarWidget 커스텀 위젯으로 만들어 화면에 표시
  • 일기 리스트: 달력 아래에 일기 리스트 출력, ListView.builder로 표시
  • 일기 작성: 새 화면에서 작성 후 결과 전달받아 리스트 갱신
  • 상세 보기: 일기 제목/내용 자세히 보기 화면 구현

4. 달력 위젯 간단 구현 예제

import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:intl/date_symbol_data_local.dart';

class CalendarWidget extends StatefulWidget {
  const CalendarWidget({Key? key}) : super(key: key);

  @override
  State<CalendarWidget> createState() => _CalendarWidgetState();
}

class _CalendarWidgetState extends State<CalendarWidget> {
  late final DateTime _focusedDay;
  DateTime? _selectedDay;

  @override
  void initState() {
    super.initState();
    _focusedDay = DateTime.now();
    _selectedDay = _focusedDay;
  }

  @override
  Widget build(BuildContext context) {
    return TableCalendar(
      locale: 'ko_KR',
      firstDay: DateTime.utc(2000, 1, 1),
      lastDay: DateTime.utc(2100, 12, 31),
      focusedDay: _focusedDay,
      selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
      onDaySelected: (selectedDay, focusedDay) {
        setState(() {
          _selectedDay = selectedDay;
          // _focusedDay = focusedDay; // 필요시 업데이트
        });
      },
      calendarFormat: CalendarFormat.month,
    );
  }
}

6. 결론

  • Flutter 달력 구현 시 intl 로케일 초기화가 가장 중요한 첫 단계
  • 렌더링 성능 문제는 상태관리와 빌드 최소화로 해결
  • 권한 문제도 사전에 반드시 확인 및 설정
  • 달력과 일기 앱 구조를 잘 설계하면 기능 확장도 편리