Flutter

flutter datepicker 선택날짜 초기화 이슈 해결

땅콩콩 2023. 8. 3. 17:12

flutter로 로컬스토리지를 사용하는 앱을 개발하며 datepicker 오픈 패키지를 커스텀해서 사용하는 과정에서 문제가 있었다.

https://github.com/sivaprasadnk/SimpleMonthYearPicker

 

GitHub - sivaprasadnk/SimpleMonthYearPicker

Contribute to sivaprasadnk/SimpleMonthYearPicker development by creating an account on GitHub.

github.com

 

기존의 CupertinoDatePicker는 일을 없애고 년과 월 옵션만 넣도록 커스텀이 안돼서 위의 오픈소스 패키지를 사용하게 되었다.

내가 구현하고자 한 기능은 datepicker를 통해 원하는 날짜를 선택하면 해당 달에 기록된 일기를 모두 조회해주는 간단한 기능이었다.

drift와 getit패키지를 사용하였고 해당부분 데이터를 조회하는 쿼리는 아래와 같다.

Stream<List<Thank>> watchMonthSelectedThanks(DateTime date){
  final query = select(thanks);
  query.where((tbl) => tbl.date.year.equals(date.year) & tbl.date.month.equals(date.month));
  query.orderBy([(tbl) => OrderingTerm(expression: tbl.date)]);
  return query.watch();
}

 

본론으로 들어가서, 해당 부분을 구현하며 파악한 문제상황은 이렇다.

 

1) datepicker를 클릭하면 현재 날짜(8월)이 디폴트로 선택되어있음. => 어딘가에서 초기값이 설정 되어있음

2) datepicker에서 다른 날짜(9월, 10월 등)를 선택하고 창을 닫으면 해당 날짜의 데이터들이 잘 조회됨 => 쿼리에는 문제가 없음

3) 다른 날짜의 데이터들이 잘 조회된 상태에서 다시 datepicker를 열면 해당날짜로 유지되어있는 것이 아니라 초기값인 8월로 선택된 날짜가 돌아가있는 것이 문제이다. (예를들어 10월을 골라 10월의 데이터들을 조회하고 다시 열면 10월이 선택되어있어야 한다.)

 

이 부분을 해결하기 위해서 우선 showMonthYearPickerDialog에 newSelectedDate변수를 추가하고 해당값을 datepicker 내부에서 사용할 수 있도록 커스텀했다.

static Future<DateTime> showMonthYearPickerDialog({
  required BuildContext context,
  TextStyle? titleTextStyle,
  TextStyle? yearTextStyle,
  TextStyle? monthTextStyle,
  Color? backgroundColor,
  Color? selectionColor,
  bool? barrierDismissible,
  bool? disableFuture,
  required DateTime newSelectedDate, //추가
}) async {
  final ThemeData theme = Theme.of(context);
  var primaryColor = selectionColor ?? theme.primaryColor;
  var bgColor = backgroundColor ?? theme.scaffoldBackgroundColor;
  // var textTheme = theme.textTheme;

  /// to get current year
  int selectedYear = newSelectedDate.year; //변경
  //    int selectedYear = DateTime.now().year; 

  /// to get index corresponding to current month (1- Jan, 2- Feb,..)
  var selectedMonth = newSelectedDate.month; //변경
  //    var selectedMonth = DateTime.now().month; 

그랬더니 이 함수를 사용하는 부분에서 초기값이 들어오지 않을 때가 문제인 상황이 발생했다.

 

그래서 이 함수가 사용되는 state 함수 내부에서 아래와 같은 구조로 이미 선택되어있는 날짜와 date picker를 통해 받아오는 날짜를 구분해서 관리할 수 있도록 구현했다.

late DateTime selectedDate;
late DateTime picked;

@override
void initState() {
  super.initState();
  selectedDate = DateTime.now();
  picked = DateTime.now();
}

final monthTextStyle = TextStyle(
  fontWeight: FontWeight.w600,
  color: Colors.black54,
  fontSize: 14.0,
);

Future<void> _selectDate(BuildContext context) async {
  picked = await SimpleMonthYearPicker
      .showMonthYearPickerDialog(
    context: context,
    titleTextStyle: monthTextStyle,
    monthTextStyle: monthTextStyle,
    yearTextStyle: monthTextStyle,
    barrierDismissible: true,
    disableFuture: true,
    backgroundColor: DEEP_BEIGE,
    selectionColor: PRIMARY_COLOR,
    newSelectedDate: picked,
  );
  if( picked != null && picked != selectedDate){
    setState(() {
      selectedDate = DateTime(picked.year, picked.month);
    });
  }
}

이렇게 해당 이슈를 해결할 수 있었다.