Flutter 개발일지 day 5

커서 구성

먼저 커서를 추가했다. 커서는 우리가 현재 바라보고 있는 달을 담아두기 위해서이다. 예를 들어 22년 12월 10일을 바라보고 있으면, 우리가 만든 42개의 컨테이너에는 12월에 관련된 일자들을 나열하고, 앞 뒤로 삐져나온 날들(11월과 내년 1월)은 안보이게 숨겨야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Cursor.dart
class Cursor{
  late DateTime selected;

  Cursor({
    required this.selected
  });

  int dayofweek(){
    final firstDay = DateTime(selected.year, selected.month, 1);
    var firstDayVal = firstDay.weekday;
    return ((selected.day+firstDayVal-2) ~/ 7) + 1;
  }

  List<DateTime> daylist() {
    DateTime firstday = DateTime(selected.year, selected.month,1);
    List<DateTime> dlist = List<DateTime>.filled(42,DateTime(0,0,0));
    int i = 0;
    int j = 2-firstday.weekday;
    while (i <= 41) {
      dlist[i] = DateTime(firstday.year, firstday.month, j++);
      i++;
    }
    return dlist;
  }

따라서, 현재 바라보고 있는 정보 (Datetime)을 담을 수 있는 selected element를 추가했고, 처음 불러올 때 Constructor에서 필수적으로 required하도록 선언했다(그래야 null safety에 안걸린다).

또한 기능을 한 곳으로 모으기 위해서(예쁘게 캡슐화하기 위해) daylist.dart 파일을 지우고 거기에 있던 GenerateDay class와 dayCal 함수를 Cursor class의 메소드로 바꾸었다. 이제 Cursor.daylist()를 통해, 해당 달에 해당하는 일자들의 list(dlist)를 리턴할 수 있다. 좀 난잡하게 위치해있던 기능이 이쁘게 잘 모인 것 같다.

이제 monthCal.dart에서, MonthCal stateful widget이 빌드되기 전에

1
2
Cursor cursor = Cursor(selected: DateTime.now());
List<DateTime> daylist = cursor.daylist();

이런 식으로 cursor을 define하고 시작하면 아래 build된 위젯에서 값들을 문제없이 불러올 수 있다.

화면 구성

앞서 말했듯, 이번 달은 온전히 이번 달만을 표시해야 한다. 저번 달과 다음 달을 표시하면 안된다는 것. 따라서, 모든 container의 child에 삼항연산자를 넣어 현재 커서값(=특정한 일자)의 month와 container에 담긴 값(=daylist[i])의 month가 같은지 비교해줘서 둘이 같을 경우에만 일자를 보여주도록 했다. 이는 1, 5, 6번째 row의 container들에만 적용된다.

1
child: daylist[i].month != cursor.selected.month ? null : MyText(daylist[i].day.toString(), 15),

같지 않으면(=다른 달이면) null을 리턴하고 같으면 일자를 담은 text를 잘 리턴한다.

코드 재구성

text를 출력할 때 매번 이것저것 요소들을 대입해주기 귀찮아서 단순화시킨 MyText 위젯을 calenderElement.dart로 이동했다. 이것도 기능의 캡슐화를 위해서이다.

ScheduleClass 추가(임시)

나중에 일정 하나하나를 담을 ScheduleClass를 임시로 추가했다. 간단하게 이름, 알람 여부 등을 인자로 갖는다. 나중에 구현 상황에 따라 변동될 가능성이 아주 큰 class이기 때문에 나중에 따로 다룰 예정.

날짜가 바뀌는 경우 확인(with FloatingActionButton)

위에 cursor 변수를 선언하는 곳에서 DateTime에 다양한 일자를 넣어보며 문제없이 캘린더 레이아웃이 구성되는 것을 확인했지만, 어플 내부에서 변수가 바뀌어도 제대로 build되는지를 확인해보려 했다. 어플 내부에서 cursor에 DateTime.now()가 아닌 다른 년도, 월 등을 대입하기 위해, FloatingActionButton을 이용했다.

1
2
3
4
5
FloatingActionButton(onPressed: () {
            setState(() {
              cursor.selected = DateTime(2021,2,1);
            });
          })

이렇게 쓰면 놀랍게도 특정 row의 날짜들만 날라간다. 커서에 새로운 값을 대입하고 setState로 위젯을 새로 build해도, daylist에는 아직 예전값이 그대로 남아있기 때문에 위에서 삼항연산자로 비교한 row의 container들만 모두 false가 되어서 날라간다. 따라서, 매번 cursor에 새로운 일자를 대입할 때마다 daylist함수를 호출해서 새로 daylist 리스트를 초기화해주어야 한다. 이건 임시로 확인하려고 만든 버튼이므로, 나중에 월, 주 등을 바꾸는 버튼에서 구현해주기로 하고 넘어갔다.

배운점

기존의 일반적인 언어들과는 다르게, dart는 어플을 직접적으로 만드는 언어(widget등을 직접 다루는)라서 매번 괴리감을 느끼고 있다. 즉 이전에 C나 python에서는 언제 어디서나 변수를 생성하고 함수를 실행할 수 있었는데(물론 정의된 범위 등에 따라 호출에 제한이 있지만), 여긴 함수부와 widget부?에 차이가 있어서 아무때나 변수를 만들거나 할 수 없어서 굉장히 답답했다. 또 화면을 구성하는 widget들을 build해야 화면에 변화가 표시되기 때문에, 변수가 하나 달라지면 그 변수를 담는 widget들을 다시 build 해줘야 하는 등 훨씬 더 신경쓸게 많았다. 확실히 여태까지 배운 프로그래밍과는 조금 다른 맥락인 것 같다.