ABOUT ME

-

  • [ Flutter ] TableCalendar 달력 커스텀
    Application/Flutter 2024. 6. 16. 17:30
    반응형

    headerStyle

    https://pub.dev/documentation/table_calendar/latest/table_calendar/HeaderStyle/HeaderStyle.html

     

    HeaderStyle constructor - HeaderStyle - table_calendar library - Dart API

    HeaderStyle constructor const HeaderStyle({ bool titleCentered = false, bool formatButtonVisible = true, bool formatButtonShowsNext = true, TextFormatter? titleTextFormatter, TextStyle titleTextStyle = const TextStyle(fontSize: 17.0), TextStyle formatButto

    pub.dev


    Implementation

    - title implementation

    titleCentered <boolean> : 월 표시인 '2024년 6월' 표시된 부분을 가운데 위치 여부

    titleTextFormatter<TextFormatter> : title 의 날짜 형태 변경

    (ex : titleTextFormatter: (date, locale) => DateFormat.yM(locale).format(date),)

    titleTextStyle<TextStyle> : title style 변경

     

    - formatButton implementation

    formatButtonVisible<boolean> : 첫 TableCalendar를 사용할때 2weeks가 적혀있는 button의 노출 여부

    formatButtonShowsNext<boolean> : formatButton 글자 제어 여부

    formatButtonTextStyle<TextStyle> : formatButton 글자 style 변경

    formatButtonDecoration<BoxDecoration> : formatButton style

    formatButtonPadding<EdgeInsets> : formatButton padding

     

    - header implementation

    headerMargin<EdgeInsets> : header margin

    headerPadding<EdgeInsets> : header padding

    decoration<BoxDecoration> : header Style

     

    - chevron implementaion

    calendar에서 양쪽 화살표의 padding, margin, icon 지정 및 노출 여부

    leftChevronPadding<EdgeInsets> 
    rightChevronPadding<EdgeInsets>
    leftChevronMargin<EdgeInsets>
    rightChevronMargin<EdgeInsets>
    leftChevronIcon<EdgeInsets>
    rightChevronIcon<EdgeInsets>

    leftChevronVisible<boolean> 

    rightChevronVisible<boolean>

     

    const HeaderStyle({
      this.titleCentered = false,
      this.formatButtonVisible = true,
      this.formatButtonShowsNext = true,
      this.titleTextFormatter,
      this.titleTextStyle = const TextStyle(fontSize: 17.0),
      this.formatButtonTextStyle = const TextStyle(fontSize: 14.0),
      this.formatButtonDecoration = const BoxDecoration(
        border: const Border.fromBorderSide(BorderSide()),
        borderRadius: const BorderRadius.all(Radius.circular(12.0)),
      ),
      this.headerMargin = const EdgeInsets.all(0.0),
      this.headerPadding = const EdgeInsets.symmetric(vertical: 8.0),
      this.formatButtonPadding =
          const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0),
      this.leftChevronPadding = const EdgeInsets.all(12.0),
      this.rightChevronPadding = const EdgeInsets.all(12.0),
      this.leftChevronMargin = const EdgeInsets.symmetric(horizontal: 8.0),
      this.rightChevronMargin = const EdgeInsets.symmetric(horizontal: 8.0),
      this.leftChevronIcon = const Icon(Icons.chevron_left),
      this.rightChevronIcon = const Icon(Icons.chevron_right),
      this.leftChevronVisible = true,
      this.rightChevronVisible = true,
      this.decoration = const BoxDecoration(),
    });

     

    우선 날짜 표시만 가운데로 하고 formatButton 노출만 안하도록 적용

     

     

        return Container(
          child: TableCalendar(
            locale: 'ko_KR',
            focusedDay: _focusedDay,
            firstDay: DateTime.utc(focusedDay.year, focusedDay.month - 3, focusedDay.day),
            lastDay: DateTime.utc(focusedDay.year, focusedDay.month + 3, focusedDay.day),
            headerStyle: HeaderStyle(
                titleCentered: true,
                formatButtonVisible: false
            ),

    SelectedDay

    https://pub.dev/documentation/table_calendar/latest/table_calendar/OnDaySelected.html

     

    OnDaySelected typedef - table_calendar library - Dart API

    OnDaySelected typedef OnDaySelected = void Function(DateTime selectedDay, DateTime focusedDay) Signature for onDaySelected callback. Contains the selected day and focused day. Implementation typedef OnDaySelected = void Function( DateTime selectedDay, Date

    pub.dev

    날짜 초기화

    DateTime selectedDay = DateTime(
        DateTime.now().year,
        DateTime.now().month,
        DateTime.now().day,
      );
      DateTime _focusedDay = focusedDay;

     

    onDaySelected는 날짜를 선택하면 selectedDay값과 focusedDay값을 받을 수 있는데,

    두개의 값을 출력해본결과 둘다 클릭한 날짜의 값이 나와서 좀 더 해봐야할 것 같음.

     

    selectedDayPredicate는 아직 어떨때 사용하는지를 정확하게 파악을 못함.

    일단 선택한 날짜의 true false값을 return해주어서 CalendarBuilder에서

    selectedBuilder가 여기서 return된 true, falser값으로 스타일을 적용 하는지 아닌지를 판단하는 것 같음.

            onDaySelected: (DateTime selectedDay, DateTime focusedDay) {
              setState((){
                this.selectedDay = selectedDay;
                this._focusedDay = focusedDay;
              });
            },
            selectedDayPredicate: (DateTime day) {
            return isSameDay(selectedDay, day);
            },

     

    반응형

    CalendarBuilder

    https://pub.dev/documentation/table_calendar/latest/table_calendar/CalendarBuilders-class.html

     

    CalendarBuilders class - table_calendar library - Dart API

    CalendarBuilders class Class containing all custom builders for TableCalendar. Constructors CalendarBuilders({FocusedDayBuilder? prioritizedBuilder, FocusedDayBuilder? todayBuilder, FocusedDayBuilder? selectedBuilder, FocusedDayBuilder? rangeStartBuilder,

    pub.dev


    기존의 calendar에서 날짜 표시가 1일, 2일 이런식으로 표시가 되어서 날짜 숫자만 표시되도록 변경한 후

    선택한 날짜 표기 및 오늘 날짜의 색상 변경

     

        return Container(
          child: TableCalendar(
            locale: 'ko_KR',
            focusedDay: _focusedDay,
            firstDay: DateTime.utc(focusedDay.year, focusedDay.month - 3, focusedDay.day),
            lastDay: DateTime.utc(focusedDay.year, focusedDay.month + 3, focusedDay.day),
            headerStyle: HeaderStyle(
                titleCentered: true,
                formatButtonVisible: false
            ),
            calendarBuilders: CalendarBuilders(
              outsideBuilder: BuildOutSideDay,
              defaultBuilder: BuildDefaultDay,
              selectedBuilder: BuildSelectedDay,
              todayBuilder: BuildToday,
            ),

     

    outsideBuilder : 현재달이 아닌 이전 및 다음달의 날짜 표기 방식 및 스타일

    defaultBuilder : 현재달 날짜 표기 방식 및 스타일

    selectedBuilder : 선택한 날짜 표기 방식 및 스타일

    todayBuilder : 오늘 날짜 표기 방식 및 스타일

     

    Widget BuildOutSideDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: Colors.grey
          ),
        ),
      );
    }
    
    Widget BuildDefaultDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: isSameDay(date, focusedDay) ? Colors.blue : Colors.black,
          ),
        ),
      );
    }
    
    Widget BuildSelectedDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(color: Colors.green),
        ),
      );
    }
    
    Widget BuildToday(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: Colors.blue,
            fontWeight: FontWeight.bold,
          ),
        ),
      );
    }

    아직 마커를 찍었지만 좀 더 마커 사용법을 익히고 해봐야할듯 함.

    전체 코드는 이렇게 되어있음.

     

    생각보다 코드가 길어지면서 calendar관련 변수들을 따로 파일로 만들어서 import하여 관리

    특히 builder부분이 너무 많음..

    import 'package:flutter/material.dart';
    import 'package:table_calendar/table_calendar.dart';
    
    import '../../utils/calendar_utils.dart';
    class CalendarComponent extends StatefulWidget {
      @override
      State<CalendarComponent> createState() => _CalendarComponentState();
    }
    
    class _CalendarComponentState extends State<CalendarComponent> {
    
    
      List<Event> _getEventsForDay(DateTime day) {
        return events[day] ?? [];
      }
    
      DateTime selectedDay = DateTime(
        DateTime.now().year,
        DateTime.now().month,
        DateTime.now().day,
      );
      DateTime _focusedDay = focusedDay;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: TableCalendar(
            locale: 'ko_KR',
            focusedDay: _focusedDay,
            firstDay: DateTime.utc(focusedDay.year, focusedDay.month - 3, focusedDay.day),
            lastDay: DateTime.utc(focusedDay.year, focusedDay.month + 3, focusedDay.day),
            eventLoader: _getEventsForDay,
            onDaySelected: (DateTime selectedDay, DateTime focusedDay) {
              setState((){
                this.selectedDay = selectedDay;
                this._focusedDay = focusedDay;
              });
            },
            selectedDayPredicate: (DateTime day) {
            return isSameDay(selectedDay, day);
            },
            calendarBuilders: CalendarBuilders(
              outsideBuilder: BuildOutSideDay,
              defaultBuilder: BuildDefaultDay,
              selectedBuilder: BuildSelectedDay,
              todayBuilder: BuildToday,
            ),
            headerStyle: HeaderStyle(
              titleCentered: true,
              formatButtonVisible: false
            ),
            calendarStyle: CalendarStyle(
              canMarkersOverflow: false,
              markerSize: 10.0,
              markersAnchor: 0.7,
              markerMargin: const EdgeInsets.symmetric(horizontal: 0.3),
              markersAlignment: Alignment.bottomCenter,
              markersMaxCount: 4,
              markerDecoration: const BoxDecoration(
                color: Colors.black,
                shape: BoxShape.circle
              ),
            ),
          ),
        );
      }
    }
    import 'package:flutter/material.dart';
    import 'package:table_calendar/table_calendar.dart';
    
    class Event {
      String title;
    
      Event(this.title);
    }
    
    Map<DateTime, List<Event>> events = {
      DateTime.utc(2024,6,13) : [ Event('title'), Event('title2') ],
      DateTime.utc(2024,6,14) : [ Event('title3') ],
    };
    
    DateTime focusedDay = DateTime.now();
    
    Widget BuildOutSideDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: Colors.grey
          ),
        ),
      );
    }
    
    Widget BuildDefaultDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: isSameDay(date, focusedDay) ? Colors.blue : Colors.black,
          ),
        ),
      );
    }
    
    Widget BuildSelectedDay(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(color: Colors.green),
        ),
      );
    }
    
    Widget BuildToday(BuildContext context, DateTime date, DateTime focusedDay) {
      return Center(
        child: Text(
          '${date.day}',
          style: TextStyle(
            color: Colors.blue,
            fontWeight: FontWeight.bold,
          ),
        ),
      );
    }
    728x90
    반응형