ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter_12. DatePicker
    > Frontend/Flutter 2023. 5. 6. 13:02

     

     

     

    0) 학습 내용

    1.  DatePicker를 사용하여 선택된 Date를 저장하기. 

     

    1)  완성된 코드

     

    import 'package:flutter/material.dart';
    import 'package:intl/intl.dart';
    
    final formatter = DateFormat.yMd();
    
    class NewExpense extends StatefulWidget {
      const NewExpense({Key? key}) : super(key: key);
    
      @override
      State<NewExpense> createState() => _NewExpenseState();
    }
    
    class _NewExpenseState extends State<NewExpense> {
      // => currently no need
      var _enteredTitle = '';
    
      void _saveTitleInput(String inputValue) {
        // since there is no change in UI, no need to use setState. => currently no need
        _enteredTitle = inputValue;
      }
    
      // need to tell Flutter to delete TextEditingController when this modal is closed => otherwise, way of wasting memory.
      final _titleController = TextEditingController();
      final _amountController = TextEditingController();
      DateTime? _selectedDate;
    
      Future<void> _presentDatePicker() async {
        final now = DateTime.now();
        final firstDate = DateTime(now.year - 1, now.month, now.day);
        // showDatePicker => Flutter's Date picker Method
        final pickedDate = await showDatePicker(
            context: context,
            initialDate: now,
            firstDate: firstDate,
            lastDate: now);
        // => showDatePicker return value of type 'future'
        // => need to async await or then method
    
        setState(() {
          _selectedDate = pickedDate;
        });
      }
    
      @override
      void dispose() {
        // dispose is a part of StatefulWidget lifecycle. called when widget is destroyed.
        _titleController.dispose();
        _amountController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              TextField(
                // onChanged: _saveTitleInput, // first way of storing text value => onChanged
                controller: _titleController,
                // second way of storing text value => controller
                maxLength: 50,
                keyboardType: TextInputType.text,
                // input tag type in JS
                decoration: const InputDecoration(
                    label: Text('Title')), // title of input (Text Field)
              ),
              Row(
                children: [
                  Expanded(
                    child: TextField(
                      // TextField wants to take as much space horizontally as possible, and Row do not restrict the amount of space  which will cause error => Expanded
                      controller: _amountController,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(
                          // 앞에 붙는 $ 표시
                          prefixText: '\$ ',
                          // title of input (Text Field)
                          label: Text('Amount')),
                    ),
                  ),
                  const SizedBox(width: 16),
                  Expanded(
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      // row controls the horizontal alignment to push content to the end
                      crossAxisAlignment: CrossAxisAlignment.center,
                      // center the content vertically.
                      children: [
                        Text(
                          _selectedDate == null
                              ? 'No Dated Date'
                              : formatter.format(
                                  _selectedDate!), // ! assume this wont be null
                        ),
                        IconButton(
                            onPressed: _presentDatePicker,
                            icon: const Icon(Icons.calendar_month))
                      ],
                    ),
                  )
                ],
              ),
              Row(
                children: [
                  TextButton(
                      onPressed: () {
                        // Navigator class's pop makes modal close
                        Navigator.pop(context);
                      },
                      child: const Text('Cancel')),
                  ElevatedButton(
                      onPressed: () {
                        print(_titleController.text);
                        print(_amountController.text);
                      },
                      child: const Text('Save Expense')),
                ],
              )
            ],
          ),
        );
      }
    }
    

     

     

    2) 기존에 만든 Title TextField 에 amount 와 Date 를 추가한다.

     

    Row(
      children: [
        Expanded(
          child: TextField(
            // TextField wants to take as much space horizontally as possible, and Row do not restrict the amount of space  which will cause error => Expanded
            controller: _amountController,
            keyboardType: TextInputType.number,
            decoration: const InputDecoration(
                // 앞에 붙는 $ 표시
                prefixText: '\$ ',
                // title of input (Text Field)
                label: Text('Amount')),
          ),
        ),
        const SizedBox(width: 16),
        Expanded(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.end,
            // row controls the horizontal alignment to push content to the end
            crossAxisAlignment: CrossAxisAlignment.center,
            // center the content vertically.
            children: [
              Text(
                _selectedDate == null
                    ? 'No Dated Date'
                    : formatter.format(
                        _selectedDate!), // ! assume this wont be null
              ),
              IconButton(
                  onPressed: _presentDatePicker,
                  icon: const Icon(Icons.calendar_month))
            ],
          ),
        )
      ],
    ),

     

    • 한 행(Row: 가로)에  2개의 열 (Column: 세로)를 가질 예정임으로, Row로 감싸준다. 
    • 이때, 1) TextField 의 경우는 최대한 많은 수평적 space를 갖는데, Row는 이를 제한하지 않음으로, 에러발생  => Expanded 사용
    • 또한, 2) 두번째 Row는 그안에 중첩된 Row (Text와 IconButton)을 가질 예정임으로 => Expanded 사용 
    • 아래 사진에서, 달력 아이콘을 선택하면 _presendDatePicker라는 함수가 실행될 예정

     

    현재 showModalBottomSheet 상황

     

    3) DatePicker (달력 클릭 시, _presentDatePicker 실행)

     

    •  달력 아이콘을 클릭하면, _presentDatePicker 함수가 실행된다.
    Future<void> _presentDatePicker() async {
      final now = DateTime.now();
      final firstDate = DateTime(now.year - 1, now.month, now.day);
      // showDatePicker => Flutter's Date picker Method
      final pickedDate = await showDatePicker(
          context: context,
          initialDate: now,
          firstDate: firstDate,
          lastDate: now);
      // => showDatePicker return value of type 'future'
      // => need to async await or then method
    
      setState(() {
        _selectedDate = pickedDate;
      });
    }

     

     

    •  showDatePicker는 달력을 보여주는 flutter 자체적인 datepicker
    • 날짜를 선택하고 OK 버튼을 누르면 값을 리턴해준다.
    • 이때 Return 되는  값의 타입은 Future이다. 
    • future는 비동기 작업의 결과이며, 미완료 ||  완료 - 두 가지 상태를  가질 수 있음.
    • 비동기 작업의 결과물: 
    • API Data 통신
    • 테이터 베이스를 거쳐 CRUD
    • 파일에서 데이터 읽기
    • 두가지 상태:    
      • 미완성 (value를 생성하기 전)
        비동기 함수를 호출하면 완료되지 않은 미래가 반환됩니다. 미래에는 함수의 비동기 작업이 완료되거나 오류가 발생하기를 기다리고 있습니다.
      • 완료(value 생성)
        비동기 작업이 성공하면 future는 값(유형 Future값으로 완료) 으로, 실패하면 오류와 함께 완료.
    • 이러한 type을 가진 future은 async-await을 통해서 작업하면 값을 받을 수 있다. 
    DateTime? _selectedDate;
    

     

    • DateTime?으로 _selectedDate를 생성하고, setState안에 Future의 값을 대입 (UI가 변경되기 때문)

     

    
    ... 생략
    
    
    Expanded(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        // row controls the horizontal alignment to push content to the end
        crossAxisAlignment: CrossAxisAlignment.center,
        // center the content vertically.
        children: [
          Text(
            _selectedDate == null
                ? 'No Dated Date'
                : formatter.format(
                    _selectedDate!), // ! assume this wont be null
          ),
          
          
          ... 생략

     

    • 삼항 연상자를 써서 _selectedDate 가 null일 경우, No Dated Date 노출되며, null이 아닐때는 intl의 formatter를 사용해서 _selectedDate을 y-M-d 형태로 format한다.
    • 이때, Dart는 해당 일자가 null일 수도 있다고 가정해서, _selectedDate 뒤에 느낌표를 붙여 절대 null이 안된다고 가정

     

     

     

     

     

     

    댓글

Designed by Tistory.