table_calendar를 사용할때 중요한 요소들만 정리. 나머지는 공식문서 참조
기본적인 코드의 구성은 문서에서 제공하는 git repo를 참고하였다.
GitHub - aleksanderwozniak/table_calendar: Highly customizable, feature-packed calendar widget for Flutter
Highly customizable, feature-packed calendar widget for Flutter - GitHub - aleksanderwozniak/table_calendar: Highly customizable, feature-packed calendar widget for Flutter
github.com
예시에 나와있는 방식에서 변형한 것은 api에서 달력에 표시할 event data를 받아온 뒤에 event map을 eventLoader에서 사용할 수 있게하는 것이다.
* eventLoader는 _getEventsForDay 메서드를 사용한다.
* _getEventsForDay 메서드는 events라는 Map을 참조한다.
* events는 LinkedHashMap을 사용하여 {"날짜" : [이벤트1, 이벤트2], ...} 구조로 이벤트 정보를 가지게 한다.
event 초기화
Map<DateTime, dynamic> events = {};
해당일의 이벤트를 가져오고 없으면 빈 리스트를 반환한다.
List<Event> _getEventsForDay(DateTime day) {
return events[day] ?? [];
}
event를 처리할 Model 생성
class Event {
final String title;
const Event(this.title);
@override
String toString() => title;
}
dio 패키지를 통해 api와 통신, events 에 넣어줄 eventSource를 준비해주는 메서드.
eventSource에 {"event발생 일" :[ "이벤트 명" ]}구조로 추가해주는 것입니다.
Future<Map<DateTime, dynamic>> fetchEventData(date) async {
var dio = Dio();
String url = serverURL! + routeName;
var formData = FormData.fromMap({
"engn_id": engnId,
"user_id": widget.userId,
"date": date,
"type": 'month',
});
final response = await dio.post(url, data: formData);
var data = response.data['data'];
Map<DateTime, dynamic> eventSource = {};
for (int i = 0; i < data.length; i++) {
DateTime date = DateTime.parse(data[i]['opert_de']); //작업 날짜를 날짜형식으로 처리
print(date);
eventSource[date] = [Event('농작업')];
}
return eventSource;
}
준비된 eventSource가 LinkedHashMap에 추가되도록하며, fetchEventData가 비동기로 처리되도록 합니다.
다 받아진 후에 화면(달력의 셀에 표시하는 UI, 그 날에 해당하는 이벤트 리스트)을 다시 그려주기 위해 setState에 이벤트를 갱신해줍니다.
void updateEvent(date) async {
dynamic hashMap = LinkedHashMap(
equals: isSameDay,
hashCode: getHashCode,
)..addAll(await fetchEventData(date));
setState(() {
events = hashMap;
_selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!)); //api 통신 이후에 선택된 작업 리스트 다시 그려줌
});
}
initState에서 updateEvent 메서드 실행.
@override
void initState() {
super.initState();
updateEvent(initDate);
_selectedDay = _focusedDay;
_selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
}
달력을 그려주는 위젯
신경썼던 부분은 다른 월로 이동할때 focus가 바뀌는 것, 이번달로 돌아왔을때 오늘을 focus 하는 것이다.
Widget _buildTableCalendar() {
return TableCalendar(
calendarBuilders: CalendarBuilders(
markerBuilder: (context, day, events) {
if (events.isEmpty) return SizedBox();
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: events.length,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(top: 30),
width: 5,
decoration: BoxDecoration(shape: BoxShape.circle, color: _getColorByEvent(events[index].toString())),
);
},
);
},
selectedBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(color: Colors.black26, borderRadius: BorderRadius.circular(10.0)),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
),
),
todayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(color: Colors.black12, borderRadius: BorderRadius.circular(10.0)),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
),
),
),
locale: 'ko-KR',
headerStyle: HeaderStyle(
headerPadding: EdgeInsets.zero,
titleTextFormatter: (date, locale) => DateFormat.yMMMM(locale).format(date),
titleCentered: true,
formatButtonVisible: false,
titleTextStyle: TextStyle(
color: Colors.black,
fontSize: 20,
fontFamily: 'NanumSquareOTF',
fontWeight: FontWeight.w700,
),
),
calendarStyle: CalendarStyle(
outsideDaysVisible: true,
// holidayTextStyle: const TextStyle(color: const Color(0xFF5C6BC0)),
// weekendTextStyle: TextStyle(color: Colors.red),
),
firstDay: kFirstDay,
lastDay: kLastDay,
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
rangeStartDay: _rangeStart,
rangeEndDay: _rangeEnd,
calendarFormat: _calendarFormat,
rangeSelectionMode: _rangeSelectionMode,
eventLoader: _getEventsForDay,
startingDayOfWeek: StartingDayOfWeek.sunday,
onDaySelected: _onDaySelected,
onRangeSelected: _onRangeSelected,
onPageChanged: (focusedDay) {
var thisMonth = DateFormat('MM').format(DateTime.now()); // ex) 04
var movedMonth = DateFormat('MM').format(focusedDay); // ex) 04
_focusedDay = focusedDay;
var requestDate = DateFormat('yyyy-MM').format(focusedDay);
setState(
() {
// 해당월 페이지에서는 선택날짜를 오늘로 지정
if (movedMonth == thisMonth) {
updateEvent(requestDate);
_selectedDay = DateTime.now();
_selectedEvents.value = _getEventsForDay(DateTime.now()); //다른 월로 넘어가면 선택일과 작업리스트를 바꿔줘야 함
} else {
// 이번달이 아닌 페이지에서는 1일이 선택
updateEvent(requestDate);
_selectedDay = focusedDay;
_selectedEvents.value = _getEventsForDay(focusedDay); //다른 월로 넘어가면 선택일과 작업리스트를 바꿔줘야 함
// _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
}
},
);
},
);
}
달력 밑에 그날의 작업을 그려주는 위젯
Widget _buildWorkRow() {
return ValueListenableBuilder<List<Event>>(
valueListenable: _selectedEvents,
builder: (context, value, _) {
if (value.isEmpty) return const SizedBox();
return InkWell(
onTap: () {
DayPopup.open(context);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: value
.map(
(item) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(item.toString()),
],
),
),
decoration: BoxDecoration(
color: _getColorByEvent(item.toString()),
borderRadius: BorderRadius.circular(10),
),
),
),
)
.toList(),
),
);
},
);
}
만약 토요일, 일요일의 색상을 각 각 지정해주고 싶다면 CalendarBuilders 속성에 다음과 같이 추가해준다.
TableCalendar(
calendarBuilders: CalendarBuilders(
defaultBuilder: (context, day, focusedDay) {
final text = day.day.toString();
return _weekendText(text, day);
},
dowBuilder: (context, day) {
final text = DateFormat.E('ko-KR').format(day);
return _weekendText(text, day);
},
...
Widget _weekendText(String text, DateTime day) {
return Center(
child: Text(
text,
style: TextStyle(
color: day.weekday == DateTime.sunday
? Colors.red
: day.weekday == DateTime.saturday
? Colors.blue
: null),
),
);
}
Reference
https://stackoverflow.com/questions/68166479/adding-events-to-table-calendar
Adding events to table_calendar
I am very new to flutter/Dart programming and am confused by the code below. I didn't write the code but I would like to use it to display event markers on the calendar grid of the table_calendar p...
stackoverflow.com
[플러터/flutter] 달력 Event 구현해보기 ( Table_calendar 라이브러리)
이번엔 event를 설정하는 방법을 알아보자. 이를 통하면 특정 날짜(DateTime)에 어떠한 형태의 객체든 귀속시켜서 관리할 수 있어서 매우 편하다.이게 무슨 말이냐? event에 넣을 객체를 우리가 직접
velog.io
https://stackoverflow.com/questions/53908405/how-to-add-a-new-pair-to-map-in-dart
How to add a new pair to Map in Dart?
I caught the following errors when adding a new pair to a Map. Variables must be declared using the keywords const, final, var, or a type name Expected to find; the name someMap is already defined...
stackoverflow.com
Flutter: Future<Map<DateTime, dynamic>> can't be assigned to Map<DateTime, dynamic>
I have a function that gets data from Firestore and adds it to a Map. And when i try to use it i got this error The argument type 'Future<Map<DateTime, dynamic>>' can't be assigned to the
stackoverflow.com
'Flutter' 카테고리의 다른 글
[Flutter] move scrollController to top or bottom; scroll 위치 이동하기 (0) | 2022.04.23 |
---|---|
[Flutter] swipe page to show next week data; 주간 달력 ; 옆으로 밀어서 다음주 데이터 보여주기 (0) | 2022.04.23 |
[Flutter] for loop in row; Row에서 반복하여 위젯을 그리기 (0) | 2022.04.21 |
[Flutter] "A RenderFlex overflowed by 143 pixels on the right." (0) | 2022.04.21 |
[Flutter] remove listview builder padding; ListView의 패딩 (0) | 2022.04.21 |