[플러터/flutter] 달력 구현하기 - Table_Calendar 라이브러리 활용

박민준·2022년 1월 22일
8

제작하고 있는 앱에서 달력을 구현할 일이 생겼다.
예전에 한번 Table 위젯을 활용해서 직접 만들어본 적이 있는데
이번에는 좀 라이브러리를 활용해보기로 마음 먹었다.

일단 달력을 구현하는 라이브러리가 꽤 많은데 Table_Calendar를 선택한 건 아래 게시물에서 추천해줬기 때문.
여러 달력 라이브러리를 비교하며 어떤 라이브러리가 제일 좋은지 추천해준다. 개꿀!
https://medium.com/flutter-community/flutter-calendar-library-comparison-c08d5ba3cc9e


(화질이 좀 깨지긴 했지만..) 팀 디자이너에게 요구 받은 건, 이런 달력이다.

하지만...
Table_Calendar의 required 파라미터만 넣어준 초기 형태는 아래와 같다... ㄷ

  • focusedDay => 첫 빌드시, 달력에서 자동으로 보여줄 날..이 포함된 영역(기본 달력은 Month기준이니깐 저 코드를 해석해보면 현재 달을 보여주겠다.
  • firstDay => 달력 구성시, 맨 처음 보여줄 날짜
  • lastDay => 달력 구성시, 맨 마지막 보여줄 날짜

_cf) 나는 한달 단위로 달력을 보여줄 것이기 때문에 일단 1월만 해놨다. 여러 달을 오고가는 달력을 만들고 싶다면 first, last day를 알아서 조정하면 된다! horizontal ListView처럼 넘기며 볼 수 있는 달력이 형성된다.

이제 차근차근 목표를 향해 나아가 보자!

1. 요일 - 한국어로 바꾸기

두가지 방법이 있다. 하나는 내가 어거지로 찾아낸 방법이고.. 하난 나중에 알게 된 더 쉬운 방법이다.

CalendarBuilders 객체 활용

이 객체는 calendarBuilders 파라미터에 넣어준다.
공식문서 설명에 따르면 애초에 UI Customization을 위해 만들어놓은 객체라고 한다. 자유도가 생각보다 정말 높으니 공식문서와 코드를 잘 뜯어보며 실험해보는 걸 추천한다.
나는 아래와 같이 활용했다.

calendarBuilders: CalendarBuilders(
          dowBuilder: (context, day) {
            switch(day.weekday){
              case 1:
                return Center(child: Text('월'),);
              case 2:
                return Center(child: Text('화'),);
              case 3:
                return Center(child: Text('수'),);
              case 4:
                return Center(child: Text('목'),);
              case 5:
                return Center(child: Text('금'),);
              case 6:
                return Center(child: Text('토'),);
              case 7:
                return Center(child: Text('일',style: TextStyle(color: Colors.red),),);
            }
          },

dowBuilder 는 요일이 있는 칸을 제어하는 곳이다.

인자로는 이런 함수가 들어간다.
Widget Function(context, DateTime)

정확한 원리는 모르겠지만 대충 이렇게 이해하면 된다.
요일이 7개니깐 저친구는 총 7번 return widget을 하는거다.
조건문 없이 그냥 단독으로

(context, day) {
	return Text('월');
}

이래 하면 요일이 다 '월'이라고 표시된다.
그러니 위에처럼 switch문으로 요일별로 컨트롤해주면 되겠지?
그럼 아래와 같이 구현된다.

국제화 기능 활용

뭐 어렵지 않다. 공식문서를 그대로 따라하면 된다. 참고할 것

이거 해주고
아래와 같이 코드를 추가해주면 된다.
localeL 'ko-KR',
daysOfWeekHeight:30 -> 한글로 바꾸니깐 잘려서 높이를 높여줬다.

TableCalendar(
      focusedDay: DateTime.now(),
      firstDay: DateTime(2022,1,1),
      lastDay: DateTime(2022,1,31),
      locale: 'ko-KR',
      daysOfWeekHeight: 30,
    );

여기까지 구현 화면

2. header 없애버리기

요일 위의 영역이 header다. 지금의 월 정보를 볼 수 있고 month ->2weeks -> 1week 이렇게 달력 form을 전환할 수 있는 버튼이 있다.

원래 위에가 기본인데 아래 코드로 세팅을 추가해서

이래 만들 수 있다. 더 여러가지 파라미터가 많으니 알아서 찾아보길!

아예 없애버릴거면 그냥

TableCalendar(
      focusedDay: DateTime.now(),
      firstDay: DateTime(2022,1,1),
      lastDay: DateTime(2022,1,31),
      locale: 'ko-KR',
      daysOfWeekHeight: 30,
      headerVisible: false
    );

headerVisible -> false로 놔주면 된다.

3. CalendarStyle 객체 활용

calendarStyle : CalendarStyle(~~~) 통해 설정할 수 있는 것들이 많다.
아래는 전체 코드

alendarStyle(
        defaultTextStyle: TextStyle(color: Colors.grey,),
        weekendTextStyle: TextStyle(color: Colors.grey),
        outsideDaysVisible: false,
        todayDecoration: BoxDecoration(
          color: Colors.transparent,
          shape: BoxShape.circle,
          border: Border.all(color: Colors.green,width: 1.5)
        ),
        todayTextStyle: TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.grey
        )
      )

defaultTextStyle/weekendTextStyle 이렇게 두개! 각각 평일과 주말 날짜의 텍스트 스타일이다. 둘 다 설정을 해주어야 한다.

outsideDaysVisible: false 이전, 혹은 다음 달의 날짜 표시여부다. false로 해주자.

todayTextStyle/todayDecoration 이건 각각 오늘의 날짜를 다루는 파라미터다.

	todayDecoration: BoxDecoration(
          color: Colors.transparent,
          shape: BoxShape.circle,
          border: Border.all(color: Colors.green,width: 1.5)
        ),
        todayTextStyle: TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.grey
        )

아래 화면 구현 완료!

추가 구현 살짝

  • availableGesture 파라미터 => AvailableGesture 타입의 enum으로 인자를 넣어준다.

기본 값은 AvailableGesture.all이고 이렇게 하면 달력 위젯 내부에서 여러가지 제스쳐 액션이 가능하다. 하지만 이러면 상위 제스쳐를 무시하게 된다. 예를 들어 리스트뷰 내의 달력 영역은 스크롤이 안 먹는다거나... 이렇게 되면 달력 면적이 크니 너무 불편해진다.

그러니 AvailableGesture.none 으로 설정해주자! 그럼 달력 내부를 통해서도 리스트뷰 스크롤이 가능하다.

  • event
    살짝 복잡하다. 공식문서를 보면 더 모르겠다. 대강 어케 하라는건진 알겠는데 처음부터 그렇게 접근하면 어려우니까 차근차근 해보자.

    eventLoader 파라미터를 추가해주면 된다.
    List Fuction(DateTime) 형태다. 결과값을 List로 반환해야 한다.

List에 값이 있는 상태로 반환이 되면 마커가 표시되고 빈 리스트가 반환되면 마커가 표시가 안된다. 지금은 짝수 날짜에만 마커만 표시되게 만들어놨다.

if문 통해서 하나하 eventLoader 안에 날짜별 마커 여부 코딩해주면 코딩이 가능하긴 한데... 공식문서에서는 더 세련된 방식으로 해놨다. 메소드를 만들고 뭐 연결되게 하고. Map 타입을 활용해서 관리하는 걸 추천하는 것 같다.

event 관련해서는 이제 다음 게시물에서 다뤄보도록 하자

profile
코린이

1개의 댓글

comment-user-thumbnail
2022년 5월 29일

안녕하세요!! 저는 코린이입니다. 혹시 eventLoder부분 짝수로 하셨는데, 제가 원하는 날짜만 체크표시하고, 나갔다와서도 그 체크가 저장될수있도록 할수는 없을까요??

답글 달기