[플러터] 캘린더 프로젝트 (2)

ho's·2022년 12월 4일
0

위 글은 코드팩토리의 강의 내용을 바탕으로 작성되었습니다.

캘린더 프로젝트 (2)

아래와 같은 화면을 만들자.

저번에 캘린더라이브러리를 이용해 달력을 화면에 띄웠다.

이번엔 커스터마이징하는 방법에 대해 알아보자.

각각의 라이브러리에는 많은 생성자가 존재한다.

강의 내용을 따라하기만 한다면, 이런 생성자와 기능들이 그냥 주어지기 때문에 쓰면 된다고 생각한다.

하지만, 달력뿐 아니라 낯선 라이브러리를 사용하면 무엇을 써야할지 모르는데 이전에도 말 했듯이, 하나하나 찾아가며 필요한 기능을 써야한다.

코드를 살펴보자.

  
  Widget build(BuildContext context) {
    final defaultBoxDeco = BoxDecoration(
      color: Colors.grey[200],
      borderRadius: BorderRadius.circular(6.0),
    );

    final defaultTextStyle = TextStyle(
      color: Colors.grey[600],
      fontWeight: FontWeight.w700,
    );

    return TableCalendar(
      focusedDay: DateTime.now(),
      firstDay: DateTime(1800),
      lastDay: DateTime(3000),
      headerStyle: HeaderStyle(
        formatButtonVisible: false,
        titleCentered: true,
        titleTextStyle: TextStyle(fontWeight: FontWeight.w700, fontSize: 16.0),
      ),
      calendarStyle: CalendarStyle(
        isTodayHighlighted: false,
        defaultDecoration: defaultBoxDeco,
        weekendDecoration: defaultBoxDeco,
        selectedDecoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(6.0),
          border: Border.all(color: PRIMARY_COLOR, width: 1.0),
        ),
        defaultTextStyle: defaultTextStyle,
        weekendTextStyle: defaultTextStyle,
        selectedTextStyle: defaultTextStyle.copyWith(color: PRIMARY_COLOR),
      ),
      onDaySelected: (DateTime selectedDay, DateTime focusedDay) {
        setState(() {
          this.selectedDay = selectedDay;
        });
      },
      selectedDayPredicate: (DateTime date) {
        if (selectedDay == null) {
          return false;
        }

        return date.year == selectedDay!.year &&
            date.month == selectedDay!.month &&
            date.day == selectedDay!.day;
      },
    );
  }
}

추가된 코드는 calendarStyle 생성자이다.

isTodayHighlighted, defaultDecoration, weekendDecoration, selectedDecoration, defaultTextStyle 등등 각각에 필요한 기능을 구현하는 시간이었다.

여기서


final defaultBoxDeco = BoxDecoration(
      color: Colors.grey[200],
      borderRadius: BorderRadius.circular(6.0),
    );

    final defaultTextStyle = TextStyle(
      color: Colors.grey[600],
      fontWeight: FontWeight.w700,
    );

위와 같이 많이 사용하는 위젯들은 미리 선언을 해놓고, 위의 내용을 조금만 수정할 경우, .copyWith를 이용해 바뀌는 부분만 수정을 해준다. 또한 자주 사용하는 색을 const 파일에 저장해 불러오는 것도 알게되었다.

버그가 존재한다.

같은 달에 있는 일자를 선택하면 잘 선택이 되는데, 다른 월,일을 선택하면 위와 같이 화면이 깨진다. 또한 전월, 다음월로 이동이 되지 않는 현상이 발생한다.

에러는 우리에게 좋은 신호다,,!

조금 더 자세히 들여다 보면,

위와 같이 설명이 되어있다.

Can't have a border radius if you're a circle

그럼 기본값이 원이니, 사각형으로 바꾸자!

아래 코드를 추가하자.

outsideDecoration: BoxDecoration(shape: BoxShape.rectangle),

잘 변경이 된다!

클릭하면 왜 이동하지 않을까?

위 에러는 생각보다 간단하게 해결이 된다.

위와 같이 focusedDay 라는 변수에 DateTime.now() 의 값을 넣어주고,

위와 같이 setState를 통해 상태변화된 값을 받아 저장한다.

다국어 설정하기

  • 메인 페이지에 아래와 같은 코드를 작성한다.
void main() async {

  WidgetsFlutterBinding.ensureInitialized();
  await initializeDateFormatting();

배너, 카드 만들기

위와 같은 모양을 만들고 싶다.

컴포넌트화 하자

calendar.dart 파일



class TodayBanner extends StatelessWidget {
  final DateTime selectedDay;
  final int scheduleCount;

  const TodayBanner(
      {super.key, required this.scheduleCount, required this.selectedDay});

  
  Widget build(BuildContext context) {
    final textStyle = TextStyle(
      fontWeight: FontWeight.w600,
      color: Colors.white,
    );

    return Container(
      color: PRIMARY_COLOR,
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '${selectedDay.year}년'
              '${selectedDay.month}월'
              '${selectedDay.day}일',
              style: textStyle,
            ),

            Text(
              '$scheduleCount',
              style: textStyle,
            ),
          ],
        ),
      ),
    );
  }
}

today_banner.dart 파일

import 'package:calendar/const/colors.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart';

class TodayBanner extends StatelessWidget {
  final DateTime selectedDay;
  final int scheduleCount;

  const TodayBanner(
      {super.key, required this.scheduleCount, required this.selectedDay});

  
  Widget build(BuildContext context) {
    final textStyle = TextStyle(
      fontWeight: FontWeight.w600,
      color: Colors.white,
    );

    return Container(
      color: PRIMARY_COLOR,
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '${selectedDay.year}년'
              '${selectedDay.month}월'
              '${selectedDay.day}일',
              style: textStyle,
            ),

            Text(
              '$scheduleCount',
              style: textStyle,
            ),
          ],
        ),
      ),
    );
  }
}

home_screen.dart 파일

import 'package:calendar/components/today_banner.dart';
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';

import '../components/calendar.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  DateTime selectedDay =
      DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day);
  DateTime focusedDay = DateTime.now();

  
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          body: Column(children: [
        Calendar(
          onDaySelected: onDaySelected,
          focusedDay: focusedDay,
          selectedDay: selectedDay,
        ),
        const SizedBox(
          height: 16.0,
        ),
        TodayBanner(scheduleCount: 3, selectedDay: selectedDay)
      ])),
    );
  }

  onDaySelected(DateTime selectedDay, DateTime focusedDay) {
    setState(() {
      this.selectedDay = selectedDay;
      this.focusedDay = selectedDay;
    });
  }
}
profile
그래야만 한다

0개의 댓글