[플러터로 달력만들기] #2. 달력 첫 화면 만들기

2022. 9. 23. 22:12Flutter

반응형

이제 만들어둔 구조 위에 달력 첫 화면을 올려보자

 

일단 제일 위에는 현재 년도와 달이 표시될 것이다

그 아래로는 요일

그 아래로는 일

 

일자는 깔끔하게 보이기 위해 6줄 고정으로 작성하도록 한다

 


필요한 변수와 함수부터 controller에 만들어보자

  var week = ["일", "월", "화", "수", "목", "금", "토"];
  static DateTime now = DateTime.now();

  RxInt year = 0.obs;
  RxInt month = 0.obs;
  RxList days = [].obs;

요일 배열과 년, 월 변수, 일 배열을 만들고 현재를 알 수 있는 now를 만들었다.

 

달력 처음 값을 계산하기위해 setFirst함수를 만든다.

이 함수는 onInit에서 불러 처음 실행 시 작동하도록 한다

setFirst(int setYear, int setMonth) {
  year.value = setYear;
  month.value = setMonth;
  insertDays(year.value, month.value);
}

설정하고 싶은 년과 달을 넣어주면 year, month에 해당 값을 저장하고 insertDays로 넘어간다.

 

insertDays에서는

1. 이번달 날 채우기

2. 이번달의 첫날이 일요일이 아니면 앞쪽 빈칸을 저번 달로 채우기

3. 이번달의 마지막 날 뒤로 빈칸이 있다면 다음 달로 채우기

이렇게 3단계를 거치게 된다.

  // 일자 계산
  insertDays(int year, int month) {
    days.clear();

    /*
      이번달 채우기
      => 이번달의 마지막날을 구해 1일부터 마지막 날까지 추기
    */
    int lastDay = DateTime(year, month + 1, 0).day;
    for (var i = 1; i <= lastDay; i++) {
      days.add({
        "year": year,
        "month": month,
        "day": i,
        "inMonth": true,
        "picked": false.obs,
      });
    }

    /*
      이번달 1일의 요일 : DateTime(year, month, 1).weekday 
      => 7이면(일요일) 상관x
      => 아니면 비어있는 요일만큼 지난달 채우기
    */
    if (DateTime(year, month, 1).weekday != 7) {
      var temp = [];
      int prevLastDay = DateTime(year, month, 0).day;
      for (var i = DateTime(year, month, 1).weekday - 1; i >= 0; i--) {
        temp.add({
          "year": year,
          "month": month - 1,
          "day": prevLastDay - i,
          "inMonth": false,
          "picked": false.obs,
        });
      }
      days = [...temp, ...days].obs;
    }

    /*
      6줄을 유지하기 위해 남은 날 채우기
      => 6*7 = 42. 42개까지
    */
    var temp = [];
    for (var i = 1; i <= 42 - days.length; i++) {
      temp.add({
        "year": year,
        "month": month + 1,
        "day": i,
        "inMonth": false,
        "picked": false.obs,
      });
    }

    days = [...days, ...temp].obs;
  }

days안에 들어가는 원소는 year(년), month(월), day(일), inMonth(이 달 내의 일자인가), picked(선택된 날짜인가)로 이루어져 있다

 


이제 만들어 둔 것들을 화면에 출력해보자

calendar.dart 에서 고치면 된다

 

먼저 appBar에 연도와 달을 표시한다

      appBar: AppBar(
        title: Text(
          controller.year.toString() + "." + controller.month.toString(),
        ),
        backgroundColor: Colors.white,
        elevation: 1,
        centerTitle: true,
        titleTextStyle: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.bold,
        ),
        toolbarHeight: 50,
      ),

다음으로는 요일을 표시한다

일요일은 빨간색으로, 토요일은 파란색으로 표시

 	Container(
                width: 350,
                margin: EdgeInsets.symmetric(vertical: 10),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    for (var i = 0; i < controller.week.length; i++)
                      Container(
                        width: 30,
                        margin: EdgeInsets.symmetric(horizontal: 10),
                        child: Text(
                          controller.week[i],
                          style: TextStyle(
                            color: i == 0
                                ? Colors.red
                                : i == controller.week.length - 1
                                    ? Colors.blue
                                    : Colors.black,
                          ),
                          textAlign: TextAlign.center,
                        ),
                      ),
                  ],
                ),
              ),

마지막으로 일자를 출력한다

(아직 구현되지 않았지만) 선택된 날은 빨간색으로 표시하고

이번 달이 아니지만 채워진 지난달과 다음 달은 회색으로 표시하도록 한다.

 	SizedBox(
                width: 350,
                child: Wrap(
                  children: [
                    for (var i = 0; i < controller.days.length; i++)
                      Container(
                        width: 30,
                        margin: EdgeInsets.symmetric(horizontal: 10, vertical: 2),
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(50),
                          color: controller.days[i]["picked"].value ? Colors.red : Colors.transparent,
                        ),
                        child: Center(
                          child: Text(
                            controller.days[i]["day"].toString(),
                            style: TextStyle(
                              color: controller.days[i]["inMonth"] ? Colors.black : Colors.grey,
                            ),
                          ),
                        ),
                      ),
                  ],
                ),
              )

이제 프로젝트를 실행하면 9월이 출력되게 된다.

아래는 결과물!

반응형