제작하고 있는 앱에서 달력을 구현할 일이 생겼다.
예전에 한번 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처럼 넘기며 볼 수 있는 달력이 형성된다.
이제 차근차근 목표를 향해 나아가 보자!
두가지 방법이 있다. 하나는 내가 어거지로 찾아낸 방법이고.. 하난 나중에 알게 된 더 쉬운 방법이다.
이 객체는 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,
);
여기까지 구현 화면
요일 위의 영역이 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로 놔주면 된다.
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.all이고 이렇게 하면 달력 위젯 내부에서 여러가지 제스쳐 액션이 가능하다. 하지만 이러면 상위 제스쳐를 무시하게 된다. 예를 들어 리스트뷰 내의 달력 영역은 스크롤이 안 먹는다거나... 이렇게 되면 달력 면적이 크니 너무 불편해진다.
그러니 AvailableGesture.none 으로 설정해주자! 그럼 달력 내부를 통해서도 리스트뷰 스크롤이 가능하다.
List에 값이 있는 상태로 반환이 되면 마커가 표시되고 빈 리스트가 반환되면 마커가 표시가 안된다. 지금은 짝수 날짜에만 마커만 표시되게 만들어놨다.
if문 통해서 하나하 eventLoader 안에 날짜별 마커 여부 코딩해주면 코딩이 가능하긴 한데... 공식문서에서는 더 세련된 방식으로 해놨다. 메소드를 만들고 뭐 연결되게 하고. Map 타입을 활용해서 관리하는 걸 추천하는 것 같다.
event 관련해서는 이제 다음 게시물에서 다뤄보도록 하자
안녕하세요!! 저는 코린이입니다. 혹시 eventLoder부분 짝수로 하셨는데, 제가 원하는 날짜만 체크표시하고, 나갔다와서도 그 체크가 저장될수있도록 할수는 없을까요??