본문 바로가기
개발자 랩실/플러터 (Flutter)

[Flutter] 달력 팝업 창 (기간 검색 시 사용)

by sina.dev 2022. 2. 11.
728x90

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
    /// 아래 2개 추가
  syncfusion_flutter_datepicker: ^19.2.60
  fluttertoast: ^8.0.3
  • 추가해야 하는 플러그인 : syncfusion_flutter_datepicker, fluttertoast
  • 추가 후 pub get 명령어로 플러그인 추가하기

DatePeriodPicker.dart

import 'package:common/common.dart';
import 'package:common/style.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';

/// 날짜 선택 위젯 (시작일, 종료일)
class DatePeriodPicker extends StatefulWidget {
  /// 날짜 상태 변경 시
  final Function(String? onValue)? onStartDateChanged;
  final Function(String? onValue)? onEndDateChanged;

  DatePeriodPicker({this.onStartDateChanged, this.onEndDateChanged});

  @override
  _DatePeriodPickerState createState() => _DatePeriodPickerState();
}

class _DatePeriodPickerState extends State<DatePeriodPicker> {
  DateTime? startDate = DateTime.now();
  DateTime? endDate = DateTime.now();
  var isAllDay = true;
  var controller = DateRangePickerController();

  Widget searchBox(
    String? title,
    Widget child,
  ) {
    return Row(
      children: [
        Expanded(
          flex: 1,
          child: Container(
            alignment: Alignment.center,
            child: Text('${title ?? ''}',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.w400,
                color: CustomColor.dark,
              ),
            ),
          ),
        ),
        Expanded(
          flex: 3,
          child: Container(
            child: child,
          ),
        ),
        SizedBox(width: 10,),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          flex: 1,
          child: Container(
            child: searchBox('시작일: ', DateInputButton(
              Formatter.date('yyyy-MM-dd', startDate),
              onTap: () => getDate(),
              disabled: startDate == null || isAllDay,
            ),)
          ),
        ),
        Expanded(
          flex: 1,
          child: Container(
            child: searchBox('종료일: ',
              DateInputButton(
                Formatter.date('yyyy-MM-dd', endDate),
                onTap: () => getDate(),
                disabled: endDate == null || isAllDay,
              ),
            )
          ),
        ),
      ],
    );
  }

  Future getDate() async {
    return showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => AlertDialog(
            /// 달력 팝업창
                    content: SizedBox(
          width: 500,
          height: 300,
          child: SfDateRangePicker(
              selectionMode: DateRangePickerSelectionMode.range,
              maxDate: DateTime.now(),
              controller: controller,
          ),
        ),
        actions: [
                    /// 달력 팝업창 하단 버튼
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text('취소'),
          ),
          TextButton(
            onPressed: () {
              var dateRange = controller.selectedRange;
              if (dateRange == null ||
                  dateRange.startDate == null ||
                  dateRange.endDate == null) {
                showToast('날짜를 올바르게 선택해주세요.');
              } else {
                setState(() {
                  isAllDay = false;
                  startDate = dateRange.startDate;
                  endDate = dateRange.endDate;
                });
                widget.onStartDateChanged
                    ?.call(Formatter.date('yyyy-MM-dd', startDate));
                widget.onEndDateChanged
                    ?.call(Formatter.date('yyyy-MM-dd', endDate));
                Navigator.pop(context);
              }
            },
            child: Text('확인'),
          ),
        ],
      ),
    );
  }
}

/// 날짜 버튼
class DateInputButton extends StatelessWidget {
  final String text;
  final bool disabled;
  final Function()? onTap;

  DateInputButton(this.text, {this.disabled = false, this.onTap});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        width: 150,
        height: 40,
        padding: EdgeInsets.symmetric(horizontal: 15),
        decoration: ShapeDecoration(
          shape: RoundedRectangleBorder(
            side: BorderSide(
              color: CustomColor.lightGrey2,
              width: 2,
            ),
            borderRadius: BorderRadius.all(
              Radius.circular(5),
            ),
          ),
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Text(
              text,
              style: TextStyle(color: CustomColor.dark),
              ),
            Icon(Icons.calendar_today_outlined),
          ],
        ),
      ),
    );
  }
}

common.dart

import 'package:diaconn_aps_control/common/style.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:intl/intl.dart';

/// 날짜 포맷
class Formatter {
  /*
    Format Pattern                    Result
    --------------                    -------
    'yyyy.MM.dd G 'at' HH:mm:ss vvvv' 1996.07.10 AD at 15:08:56 Pacific Time
    'EEE, MMM d, ''yy'                Wed, Jul 10, '96
    'h:mm a'                          12:08 PM
    'hh 'o''clock' a, zzzz'           12 o'clock PM, Pacific Daylight Time
    'K:mm a, vvv'                     0:00 PM, PT
    'yyyyy.MMMMM.dd GGG hh:mm aaa'    01996.July.10 AD 12:08 PM
  */
  static String date(String pattern, date) {
    try {
      late DateTime dateTime;
      if (date is DateTime) {
        dateTime = date;
      }else if(date is String){
        if(date.length == 14){
          String dateFirst = date.substring(0,8);
          String dateSecond = date.substring(8,14);
          dateTime = DateTime.parse('$dateFirst $dateSecond');
        }else{
          dateTime = DateTime.parse(date);
        }
      }
      return DateFormat(pattern).format(dateTime);
    } on FormatException catch (e) {
      print('Formatter.date(pattern, date <== 여기문제) 제대로 된 날짜형식이 아닙니다.');
      throw e;
    }
  }

  static String currentDate(String pattern) {
    return DateFormat(pattern).format(DateTime.now());
  }
}

/// 미니 알림창 
Future<void> showToast(String message) async {
  await Fluttertoast.showToast(
    msg: message,
    backgroundColor: CustomColor.background,
  );
}

styles.dart

import 'package:flutter/material.dart';

/// 사용자 정의 컬러
class CustomColor {

  /// Dark
  static const Color dark = Color(0xff020203);

  /// Blue
  static const Color lightBlue = Color(0xff6EC7C5);
  static const Color lightBlue2 = Color(0xff81D3F9);
  static const Color neonBlue = Color(0xff20c5e7);

  /// Orange
  static const Color lightOrange = Color(0xffFBD29C);
  static const Color lightOrange2 = Color(0xffE4A24A);

  /// Grey
  static const Color lightGrey = Color(0xffF2F2F2);
  static const Color lightGrey2 = Color(0xffE2E2E2);
  static const Color lightGrey3 = Color(0xff666672);
  static const Color lightGrey4 = Color(0xffC2C2C2);

  static const Color background = Color(0xff313b48);

  /// White
  static const Color white = Color(0xFFFFFFFF);
  static const Color white2 = Color(0xfff5f5f5);

  /// Red
  static const Color red = Color(0xFFC62828);

  static const Color disabled = Color(0xff6e7f92);
}

실행 결과

  • 검색 조건의 UI 틀은 DatePeriodPicker.dart 코드에서 Column 부분을 수정하면 된다.

댓글