728x90
반응형
AlertDialog에서TableCalendar를 쓸 때 날짜 선택 반영이 잘 안되는 점을 발견해 해결한 과정 공유 해봄니다
우선, AlertDialog의 child가 아니라 아래처럼 그냥 TableCalendar만 쓰면 문제 없이 날짜 선택이 됩니다.
더보기
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:intl/intl.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CalendarScreen(),
);
}
}
class CalendarScreen extends StatefulWidget {
@override
_CalendarScreenState createState() => _CalendarScreenState();
}
class _CalendarScreenState extends State<CalendarScreen> {
DateTime _selectedDay = DateTime.now();
DateTime _focusedDay = DateTime.now();
CalendarFormat _calendarFormat = CalendarFormat.month;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Calendar Example'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TableCalendar(
onPageChanged: (focusedDay) {
setState(() {
_focusedDay = focusedDay;
});
},
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
calendarFormat: _calendarFormat,
onFormatChanged: (format) {
if (_calendarFormat != format) {
setState(() {
_calendarFormat = format;
});
}
},
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: _focusedDay,
),
SizedBox(height: 16.0),
Text(
'Selected day: ${DateFormat('yyyy-MM-dd').format(_selectedDay)}',
style: TextStyle(fontSize: 20),
),
],
),
),
);
}
bool isSameDay(DateTime? day1, DateTime? day2) {
if (day1 == null || day2 == null) {
return false;
}
return day1.year == day2.year && day1.month == day2.month && day1.day == day2.day;
}
}
하지만, 아래처럼 AlertDialog의 child로 TableCalendar를 만들면, 날짜 선택 후 다른 달로 옮겼다가 선택한 날짜가 있는 달로 돌아와야 선택한 날짜에 마크가 되는 기이한 현상이 발생합니다(?)
(대강 elevatedbutton 하나 만들어서 onpressed 속성에 아래의 _showCalendar 함수 넣고 실행해보세요 진짜 신기합니다)
더보기
void _showCalendar() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: SizedBox(
width: MediaQuery.of(context).size.width * 0.8, // 화면 너비의 80%
height: MediaQuery.of(context).size.height * 0.6, // 화면 높이의 60%
child: TableCalendar(
onPageChanged: (focusedDay) {
_focusedDay = focusedDay;
},
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
calendarFormat: _calendarFormat,
onFormatChanged: (format) {
if (_calendarFormat != format) {
// Call `setState()` when updating calendar format
setState(() {
_calendarFormat = format;
});
}
},
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: _focusedDay,
),
),
);
},
);
}
이번에 새로나온 chat gpt 4-o의 도움을 받으니,
showDialog안에 StatefulBuilder를 사용해서 setState를 다이얼로그 내에서 사용해 상태 변경을 즉시 반영하고 UI를 업데이트 해주라고 합니다.
이렇게 쓰게 되면 별도의 BuildContext를 가지게 되고 StatefulBuilder의 setState가 다이얼로그 내에서만 영향을 미치므로, 다이얼로그 내의 특정 위젯들만 다시 렌더링하게 되어 문제없이 작동됩니다.
~해결한 코드 첨부~
더보기
void _showCalendar() {
void _showCalendar() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return SizedBox(
width: MediaQuery.of(context).size.width * 0.8, // 화면 너비의 80%
height: MediaQuery.of(context).size.height * 0.6, // 화면 높이의 60%
child: TableCalendar(
onPageChanged: (focusedDay) {
_focusedDay = focusedDay;
},
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
calendarFormat: _calendarFormat,
onFormatChanged: (format) {
if (_calendarFormat != format) {
// Call `setState()` when updating calendar format
setState(() {
_calendarFormat = format;
});
}
},
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),
focusedDay: _focusedDay,
),
);
}),
);
});
}
728x90
반응형
'Flutter' 카테고리의 다른 글
[Flutter] Column안에서 바로 ListView를 쓰지 말아야 하는 이유 (0) | 2024.11.14 |
---|---|
[Flutter] 밀어서 잠금해제 슬라이더(unlock slider) 구현하기 (0) | 2024.11.14 |
[Flutter] Geolocator 플러그인으로 위치 정보 파악하기 (0) | 2024.11.13 |
[Flutter] 안드로이드 에뮬레이터 app:compileDebugKotlin / org.jetbrains.kotlin.compilerRunner 오류 해결하기 (0) | 2024.11.10 |
[Flutter] Stream Builder에서 TypeError (Null check operator used on a null value) 가 뜨는 경우 해결법 (2) | 2024.11.10 |