Flutter UI 개선: TableCalendar에 2주 보기 옵션 넣는 방법

2024. 12. 18. 16:40같이 공부합시다 - Flutter/Flutter로 To-Do 앱 만들기

728x90

자, 이번 시간에는 Flutter를 사용해 To-Do 리스트 앱에 캘린더 기능을 조금 더 개선해 보도록 합시다.
 
 
 

Flutter UI 개선: TableCalendar에 2주 보기 옵션 넣는 방법

 
 

🔸 문제점

캘린더를 추가하면 캘린더 위쪽에 “2 Weeks” 버튼이 기본적으로 제공되는 것을 볼 수 있어요.
자동으로 구현된다면 좋겠지만 동작될 수 있도록 추가 구현이 필요합니다.
 
<현재 캘린더 내 ‘2주 보기’ 버튼>


 
<버튼을 누르면 오류가 발생된다.>


 
아예 없으면 모를까 떡하니 버튼이 있는데,
눌렀을 때 아무런 동작을 하지 않으면 사용자는 “오류네!” 하겠죠.
 
안될 말입니다. 바로 개선해 봅시다.


📌 참고

TableCalendar에서 기본적으로 제공되는
모든 보기 형식(month, twoWeeks, week)을 활성화하려면 availableCalendarFormats 속성을 설정하지 않거나, 명시적으로 추가하면 됩니다. 기본적으로 세 가지 보기 형식은 이미 포함되어 있습니다.

우리는 이미 알고 있기 때문에 availableCalendarFormats 속성은 생략하도록 하겠습니다.


TableCalendar에서 FormatButton(보기 전환 버튼)을 사용하려면, 반드시 onFormatChanged 콜백을 제공해야 합니다. 이 콜백은 사용자가 보기 형식을 전환할 때 호출됩니다.
 
TableCalendar 위젯에서 onFormatChanged를 추가하여 보기 형식이 변경될 때 이를 처리하도록 설정하세요.
 
 


🔸_calendarFormat 추가

  • State 클래스에 _calendarFormat 변수를 추가해 현재 캘린더 형식을 저장합니다.
CalendarFormat _calendarFormat = CalendarFormat.month;

 
<_calendarFormat 선언 위치 확인>


 
 
 


🔸calendarFormat: _calendarFormat

TableCalendar 위젯 안에 위에서 선언한 캘린더 포맷 기본값을 속성에 설정합니다.
 
<calendarFormat 속성 설정>


 
 
 
 


🔸onFormatChanged 콜백

  • 캘린더 보기 형식이 변경되면 호출됩니다.
  • _calendarFormat 값을 업데이트하여 선택된 보기 형식을 유지합니다.
onFormatChanged: (format) {
  if (_calendarFormat != format) {
    setState(() {
      _calendarFormat = format; // 선택된 보기 형식을 저장
    });
  }
},

 
<onFormatChanged 속성 설정>


 
여기까지 설정하면 캘린더를 닫았다가 열어야만 캘린더 보기 형식이 바뀝니다.

불편하겠죠?
당연히 버튼을 눌렀을 때 바로 반영되어야 합니다.
 
 
 


캘린더 보기가 버튼을 누른 즉시 변경되도록 하려면,
TableCalendar를 표시하는 모달 화면의 상태를 실시간으로 업데이트하도록 수정해야 합니다.
 
showModalBottomSheet에서 setState 호출이 반영되도록, 다음과 같이 StatefulBuilder 를 사용해 TableCalendar 상태를 즉시 반영할 수 있도록 만듭니다.
 

void _showCalendar() {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) {
      return StatefulBuilder(
        builder: (BuildContext context, StateSetter setModalState) {
          return Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                TableCalendar(
                  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: const BoxDecoration(
                              color: Colors.redAccent,
                              shape: BoxShape.circle,
                            ),
                          ),
                        );
                      }
                      return null;
                    },
                  ),
                  focusedDay: _focusedDay,
                  firstDay: DateTime(2000),
                  lastDay: DateTime(2100),
                  calendarFormat: _calendarFormat,
                  onFormatChanged: (format) {
                    if (_calendarFormat != format) {
                      setModalState(() {
                        _calendarFormat = format;
                      });
                      setState(() {
                        _calendarFormat = format; // 부모 상태에도 저장
                      });
                    }
                  },
                  selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
                  onDaySelected: (selectedDay, focusedDay) {
                    setState(() {
                      _selectedDay = selectedDay;
                      _focusedDay = focusedDay;
                    });
                    _showTasksForSelectedDay();
                  },
                ),
              ],
            ),
          );
        },
      );
    },
  );
}

 

 


🔸showModalBottomSheet 에 StatefulBuilder 리턴하기

Wrap 기능 기억나시나요? 아주 편리한 래핑 기능이죠 !
기존 Padding 위젯에 커서 올리고 왼쪽에 전구 아이콘 클릭하면 나옵니다.
일단 Wrap with Builder 로 감싸놓고, StatefulBuilder 로 변경하면 됩니다.
 
 
 


🔸onFormatChanged 속성 변경

  • setModalState를 호출해 모달 내부의 상태를 즉시 업데이트합니다.
  • setState를 호출해 부모 상태에도 저장하여 닫았다가 다시 열 때도 변경된 상태가 유지되도록 했습니다.
                  onFormatChanged: (format) {
                    if (_calendarFormat != format) {
                      setModalState(() {
                        _calendarFormat = format;
                      });
                      setState(() {
                        _calendarFormat = format; // 부모 상태에도 저장
                      });
                    }
                  },

 
 
 


이제 사용자가 2 weeks 또는 1 week 버튼을 누르면, 캘린더 보기가 바로 업데이트됩니다.
 
여기까지~ 고생하셨습니다 !
 
끝 !
 
GitHub : todo_app/lib/main.dart at main · SteadyBuilder/todo_app

728x90