플러터 화면이동 및 날짜 선택(Navigator, DatePicker) – 일기장 앱 만들기 (4)

플러터(Flutter)는 다양한 화면 간 전환을 간단하게 다룰수 있는 Navigator 클래스를 제공한다. Navigator 를 사용하면 사용자가 앱 내에서 다양한 화면으로 이동하고 화면 간 데이터를 전달하며 스택 기반의 화면 관리를 손쉽게 수행 할 수 있다. 이번 포스트에서는 Navigator 를 사용하여 플러터 화면이동 방법과 DatePicker 을 이용하여 날짜를 선택하는 방법에 대해 작성한다.

화면 전환 기본 사용법과 Navigator와 PageRouteBuilder의 차이점에 대한 내용입니다 참고부탁드립니다.

Navigator은 새로운 화면을 이동하고 다시 이전 화면으로 돌아오는 기능이다. 달력이 있는 메인페이지에 버튼을 추가하고 Navigator을 이용하여 입력페이지로 화면이동 할 수 있도록 하였다.

플러터-화면이동-flutter-navigator

아래 코드 부분은 화면 전환을 수행하는 부분으로 FloatingActionButton을 클릭했을때 DiarySheet 화면으르 이동하기 위해 Navigator.push을 사용하였다. push 메서드는 현재 화면을 스택에 저장하고 새로운 화면으로 이동한다.

# screens/home_screen.dart

...
  @override
  Widget build(BuildContext context) {
    // 현재 디바이스의 스크린 너비와 높이 값을 가져옴
    double screenWidth = MediaQuery.of(context).size.width;
    double screenHeight = MediaQuery.of(context).size.height;

    // Scaffold를 사용하여 화면의 구조를 정의
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.menu),    // 메뉴 버튼 아이콘 설정
          onPressed: () {
            print('menu button is clicked');  // 메뉴 버튼 클릭 시 출력할 메시지
          },
        ),
        title: Text('Diary'),  // 상단 앱 바에 표시될 타이틀 설정
      ),
      body: Center(
          child: SizedBox(
              width: screenWidth * 0.9,  // 화면 너비의 90%로 설정
              height: screenHeight * 0.7, // 화면 높이의 70%로 설정
              child: MainCalendar(
                selectedDate: selectedDate, // MainCalendar에 현재 선택된 날짜 전달
                onDaySelected: onDaySelected, // MainCalendar에서 날짜 선택 시 호출될 콜백 함수 설정
              ))),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
                builder: (_) => DiarySheet(selectedDate: selectedDate)),
          );
        },
        child: const Icon(Icons.add),  // 플로팅 액션 버튼에 '+' 아이콘 설정
      ),
    );
  }
...

입력페이지 구성

버튼을 클릭했을 때 이동되는 위젯의 화면을 구성했다. 화면의 상단에는 이전 달력에서 선택된 값을 표시하고, 아래에는 텍스트를 입력할 수 있는 입력 폼이 구성하였다. 그리고 입력한 텍스트를 저장하기 위한 버튼도 화면에 추가하였다.

플러터-화면이동-flutter-navigator-form

다음은 입력화면에 대한 코드부분이다. AppBar, ElevatedButton, TextField으로 구성되어있다. Flutter는 위젯을 조합하여 화면을 빌드한다. 코드의 구조와 UI가 직관적이기 때문에 코드를 이해 하기가 쉽다.

# widgets/diary_sheet.dart

...
 @override
  Widget build(BuildContext context) {
    // Scaffold를 사용하여 화면의 구조를 정의
    return Scaffold(
      appBar: AppBar(
        title: Text(''),  // 상단 앱 바에 표시될 타이틀 설정
      ),
      body: SafeArea(
        child: Column(
          children: [
            Container(
              margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
            ),
            ElevatedButton(
              child: Text(
                // 선택된 날짜를 'YYYY-MM-DD' 형식으로 표시
                "${widget.selectedDate.year.toString()}-${widget.selectedDate.month.toString().padLeft(2, '0')}-${widget.selectedDate.day.toString().padLeft(2, '0')}"
              ),
              onPressed: () {
                // 버튼 클릭 시 수행될 동작 (아직 구현되지 않음)
              },
            ),
            Container(
              alignment: Alignment.center,
              padding: EdgeInsets.all(20),
              child: Column(
                children: [
                  ButtonBar(),  // 버튼들을 가로로 나열하는 위젯
                  TextField(
                    controller: TextEditingController(),
                    keyboardType: TextInputType.multiline,
                    maxLines: 25,  // 최대 25줄까지 입력 가능한 텍스트 필드
                    decoration: InputDecoration(
                      hintText: "Enter Remarks",  // 힌트 텍스트 설정
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      print('submit');  // ElevatedButton 클릭 시 콘솔에 'submit' 출력
                    },
                    child: Text('Save'),  // 버튼에 표시될 텍스트 설정
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
...

DatePicker 기능추가

DatePicker는 Flutter 앱에서 날짜 및 시간을 선택 할 수 있는 팝업으로 위에 날짜 버튼을 클릭하면 날짜를 선택할 수 있도록 기능을 추가하였다. onPressed()에 사용자가 버튼을 눌렀을때 selectedDate 비동기 함수를 호출 한다.

플러터-날짜선택-flutter-datepicker

DatePicker에 사용된 인수는 다음과 같다.

  • context: context: 현재 컨텍스트를 전달하여 DatePicker를 현재 화면에 표시
  • initialDate: date: DatePicker가 표시될 때 초기 날짜
  • firstDate: DateTime(2000): 선택 가능한 날짜의 범위 중 가장 작은 날짜
  • lastDate: DateTime(2030): 선택 가능한 날짜의 범위 중 가장 큰 날짜
# widgets/diary_sheet.dart

...
Future<void> selectDate(BuildContext context, DateTime date,
      Function(DateTime) onDateSelected) async {
    // showDatePicker를 사용하여 사용자에게 날짜를 선택할 수 있는 다이얼로그 표시
    final selectedDate = await showDatePicker(
      context: context,
      initialDate: date,        // 초기 날짜 설정
      firstDate: DateTime(2000), // 선택 가능한 첫 번째 날짜 설정
      lastDate: DateTime(2030),  // 선택 가능한 마지막 날짜 설정
    );

    // 사용자가 날짜를 선택한 경우
    if (selectedDate != null) {
      // onDateSelected 콜백 함수를 호출하여 선택된 날짜를 전달
      onDateSelected(selectedDate);
    }
  }
...

사용자가 날짜를 선택하고 OK버튼을 누른경우 selectedDate변수는 선택한 날짜를 onDateselected 함수를 호출하여 저장하게 된다.

# widgets/diary_sheet.dart

...
onPressed: () {
  // selectDate 함수를 호출하여 사용자에게 날짜 선택 다이얼로그 표시
  selectDate(context, date, (selectedDate) {
    // 선택된 날짜를 상태에 반영하여 다이얼로그를 닫으면 화면에 표시
    setState(() {
      date = selectedDate;
    });
  });
...

상단 버튼에 표시된 widget.selectedDate 값은 이전 페이지에서 가져온 것이며, DatePicker에서 날짜를 선택해도 이 값이 변경되지 않는 문제가 발생하였다. 그렇기 때문에 initState메서드 호출하여 상위 클래스의 초기화 작업을 수행해야한다. date변수를 widget.selectedDate로 초기화하고 DatePicker에서 선택한 날짜를 date 변수로 업데이트하여 해결 하였다.

# widgets/main_calendar.dart

...
@override
void initState() {
  super.initState();
  date = widget.selectedDate; // date를 selectedDate로 초기화
}
...

Table_Calendar에서 Navigator기능 추가

달력에서 날짜를 클릭할 때도 입력폼 페이지로 이동하도록 하였다. onDaySelected 속성에서 DiarySheet 화면으르 이동하기 위해 Navigator.push을 사용하였다.

# widgets/main_calendar.dart

Widget build(BuildContext context) {
  // TableCalendar 위젯을 사용하여 달력을 표시
  return TableCalendar(
    // 날짜가 선택되었을 때 호출되는 함수를 설정
    onDaySelected: (selectedDate, focusedDate) {
      // DiarySheet 화면으로 이동하는 내비게이션을 수행
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (_) => DiarySheet(selectedDate: selectedDate),
        ),
      );
    },
    // 선택된 날짜를 강조하기 위한 조건 함수 설정
    selectedDayPredicate: (date) {
      return isSameDay(selectedDate, date);
    },
    // 달력의 시작 날짜와 마지막 날짜 설정
    firstDay: DateTime(2000, 1, 1),
    lastDay: DateTime(2200, 1, 1),
    // 현재 날짜를 기준으로 달력을 표시
    focusedDay: DateTime.now(),
    // 달력 헤더의 스타일 설정
    headerStyle: HeaderStyle(
      titleCentered: true,        // 타이틀을 가운데 정렬
      formatButtonVisible: false, // 헤더에 있는 버튼 숨김
      titleTextStyle: TextStyle(   // 타이틀 텍스트 스타일 설정
        fontWeight: FontWeight.w700, // 타이틀 텍스트 두께
        fontSize: 20.0,               // 타이틀 텍스트 크기
      ),
    ),
  );
}

마무리

이번 포스트에서는 Flutter의 Navigator를 통해 화면 간 전환을 다루는 방법을 살펴봤습니다. 이를 통해 앱 내에서 화면 관리를 간단하게 수행할 수 있습니다. 다음글에서는 더욱 다양한 Flutter 기능에 대해 작성하겠습니다. 감사합니다.

전체 코드는 링크에서 확인할 수 있습니다.

Leave a Comment