当前位置:   article > 正文

Flutter 时间选择组件_flutter筛选组件

flutter筛选组件

Flutter 应用开发过程中,或多或少的都会涉及到时间选择器相关的内容。Flutter默认提供了DatePicker日期选择器,如果对样式没有特殊的要求,那么可以使用它来进行时间的选择,默认的样式如下所示。
在这里插入图片描述
使用示例代码如下:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';

class DateTimeDemo extends StatefulWidget {
  @override
  _DateTimeDemoState createState() => _DateTimeDemoState();
}

class _DateTimeDemoState extends State<DateTimeDemo> {
  DateTime selectedDate = DateTime.now();
  TimeOfDay selectedTime = TimeOfDay(hour: 9, minute: 30);
  
  Future<void> _selectDate() async {
    final DateTime date = await showDatePicker(
      context: context,
      initialDate: selectedDate,
      firstDate: DateTime(1900),
      lastDate: DateTime(2100),
    );

    if (date == null) return;

    setState(() {
      selectedDate = date;
    });
  }

  Future<void> _selectTime() async {
    final TimeOfDay time = await showTimePicker(
      context: context,
      initialTime: selectedTime,
    );

    if (time == null) return;

    setState(() {
      selectedTime = time;
    });
  } 
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('DateTimeDemo'),
        elevation: 0.0,
      ),
      body: Container(
        padding: EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                InkWell(
                  onTap: _selectDate,
                  child: Row(
                    children: <Widget>[
                      Text(DateFormat.yMMMMd().format(selectedDate)),
                      Icon(Icons.arrow_drop_down),
                    ],
                  ),
                ),
                InkWell(
                  onTap: _selectTime,
                  child: Row(
                    children: <Widget>[
                      Text(selectedTime.format(context)),
                      Icon(Icons.arrow_drop_down),
                    ],
                  ),
                ),
              ],
            ),
          ],
        ),
      )
    );
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

可以发现,默认的样式并不是很友好。通常在移动应用开发中,App的涉及多是参考iOS的设计来的,所以这时候,多半需要进行自定义组件了。不管,为了快速的进行开发我们可以选择一些第三方的组件库,如flutter_custom_calendar,此库具有如下的功能:

  • 支持公历,农历,节气,传统节日,常用节假日
  • 日期范围设置,默认支持的最大日期范围为1971.01-2055.12
  • 禁用日期范围设置,比如想实现某范围的日期内可以点击,范围外的日期置灰
  • 支持单选、多选模式,提供多选超过限制个数的回调和多选超过指定范围的回调。
  • 跳转到指定日期,默认支持动画切换
  • 自定义日历Item,支持组合widget的方式和利用canvas绘制的方式
  • 自定义顶部的WeekBar
  • 根据实际场景,可以给Item添加自定义的额外数据,实现各种额外的功能。比如实- 现进度条风格的日历,实现日历的各种标记
  • 支持周视图的展示,支持月份视图和星期视图的展示与切换联动

如下是部分效果图:
在这里插入图片描述
实际使用时,我们需要根据样式对该库进行二次开发,首先,新建一个date_picker_widget.dart文件,然后添加如下代码:

import 'package:flutter/material.dart';
import 'package:flutter_custom_calendar/flutter_custom_calendar.dart';

class DatePickerWidget extends StatefulWidget {
  final ValueSetter<String> onSetter;
  DatePickerWidget({@required this.onSetter});
  @override
  _DatePickerWidgetState createState() => _DatePickerWidgetState();
}

class _DatePickerWidgetState extends State<DatePickerWidget> {
  ValueNotifier<String> text;
  ValueNotifier<String> selectText;

  CalendarController controller ;
  @override
  Widget build(BuildContext context) {
    return  Column(
      children: <Widget>[
        Container(
          color: Colors.white,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              IconButton(icon: Icon(Icons.navigate_before), onPressed: (){
                controller.moveToPreviousMonth();
              }),
              ValueListenableBuilder(
                  valueListenable: text,
                  builder: (context, value, child) {
                    return Text(text.value);
                  }),
              IconButton(
                  icon: Icon(Icons.navigate_next),
                  onPressed: () {
                    controller.moveToNextMonth();
                  }),
            ],
          ),
        ),
        CalendarViewWidget(
          boxDecoration: BoxDecoration(
              color: Colors.white
          ),
          calendarController: controller,
          weekBarItemWidgetBuilder: () {
            return CustomStyleWeekBarItem();
          },
          dayWidgetBuilder: (dateModel) {
            return CustomStyleDayWidget(dateModel);
          },
        ),
      ],
    );
  }

  List<DateTime> getHighlightedDates() {
    return List<DateTime>.generate(10,
          (int index) => DateTime.now().add(Duration(days: 10 * (index + 1))),
    );
  }

  int maxSelectYear() {
    return DateTime.now().year;
  }

  int maxSelectMounth() {
    return DateTime.now().month;
  }

  int maxSelectDay() {
    return DateTime.now().day;
  }


  @override
  void initState() {
    super.initState();
    controller =  CalendarController(
      maxSelectYear: maxSelectYear(),
      maxSelectMonth: maxSelectMounth(),
      maxSelectDay:maxSelectDay(),
    );

    controller.addMonthChangeListener(
          (year, month) {
        text.value = "$year年$month月";
      },
    );
    controller.addOnCalendarSelectListener((dateModel){
      String month = dateModel.month < 10 ? '0${dateModel.month}': '${dateModel.month}';
      String day = dateModel.day < 10 ? '0${dateModel.day}': '${dateModel.day}';
      this.widget.onSetter('${dateModel.year}-${month}-${day}');
    });

//    controller.addOnCalendarSelectListener((dateModel) {
//      debugPrint(dateModel.toString()+'+++++++++++');
//      //刷新选择的时间
//      selectText.value =
//      "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}";
//    });
//
    text = new ValueNotifier("${DateTime.now().year}年${DateTime.now().month}月");
//
//    selectText = new ValueNotifier(
//        "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}");
  }
}

class CustomStyleWeekBarItem extends BaseWeekBar {
  final List<String> weekList = ["日","一", "二", "三", "四", "五", "六",];

  @override
  Widget getWeekBarItem(int index) {
    return Container(
      child: Center(
        child: Text(weekList[index]),
      ),
    );
  }
}

class CustomStyleDayWidget extends BaseCustomDayWidget {
  CustomStyleDayWidget(DateModel dateModel) : super(dateModel);

  @override
  void drawNormal(DateModel dateModel, Canvas canvas, Size size) {
    if (!dateModel.isCurrentMonth) {
      return;
    }
    bool isWeekend = dateModel.isWeekend;
    bool isInRange = dateModel.isInRange;

    //顶部的文字
    TextPainter dayTextPainter = new TextPainter()
      ..text = TextSpan(
          text: dateModel.day.toString(),
          style: new TextStyle(
              color: !isInRange
                  ? Colors.grey
                  : isWeekend ? Colors.blue : Colors.black,
              fontSize: 16))
      ..textDirection = TextDirection.ltr
      ..textAlign = TextAlign.center;

    dayTextPainter.layout(minWidth: size.width, maxWidth: size.width);
    dayTextPainter.paint(canvas, Offset(0, 10));

    //下面的文字
    TextPainter lunarTextPainter = new TextPainter()
      ..text = new TextSpan(
          text: dateModel.lunarString,
          style: new TextStyle(
              color: !isInRange
                  ? Colors.grey
                  : isWeekend ? Colors.blue : Colors.grey,
              fontSize: 12))
      ..textDirection = TextDirection.ltr
      ..textAlign = TextAlign.center;

    lunarTextPainter.layout(minWidth: size.width, maxWidth: size.width);
    lunarTextPainter.paint(canvas, Offset(0, size.height / 2));
  }

  @override
  void drawSelected(DateModel dateModel, Canvas canvas, Size size) {
    if (!dateModel.isCurrentMonth) {
      return;
    }
    //绘制背景
    Paint backGroundPaint = new Paint()
      ..color = Colors.blue
      ..strokeWidth = 2;
    double padding = 8;
    canvas.drawCircle(Offset(size.width / 2, size.height / 2),
        (size.width - padding) / 2, backGroundPaint);

    //顶部的文字
    TextPainter dayTextPainter = new TextPainter()
      ..text = TextSpan(
          text: dateModel.day.toString(),
          style: new TextStyle(color: Colors.white, fontSize: 16))
      ..textDirection = TextDirection.ltr
      ..textAlign = TextAlign.center;

    dayTextPainter.layout(minWidth: size.width, maxWidth: size.width);
    dayTextPainter.paint(canvas, Offset(0, 10));

    //下面的文字
    TextPainter lunarTextPainter = new TextPainter()
      ..text = new TextSpan(
          text: dateModel.lunarString,
          style: new TextStyle(color: Colors.white, fontSize: 12))
      ..textDirection = TextDirection.ltr
      ..textAlign = TextAlign.center;

    lunarTextPainter.layout(minWidth: size.width, maxWidth: size.width);
    lunarTextPainter.paint(canvas, Offset(0, size.height / 2));
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201

然后,我们新建一个date_picker_dialog.dart的Dialog自定义组件,代码如下:

import 'package:flutter/material.dart';
import 'package:gc_data_app/pages/views/gaps.dart';
import 'package:gc_data_app/res/colors.dart';
import 'package:gc_data_app/routes/app_route.dart';
import 'package:gc_data_app/utils/date_utils.dart';
import 'package:gc_data_app/widgets/date_picker_new_widget.dart';
import 'package:gc_data_app/widgets/date_picker_widget.dart';
import 'package:gc_data_app/widgets/drop_down_widget.dart';
import 'package:toast/toast.dart';

class DatePickerDialog extends StatefulWidget {

  const DatePickerDialog({
    Key key,
    @required this.onSelectedDate,
  }) : super(key: key);

  final Function(String) onSelectedDate;

  @override
  State<StatefulWidget> createState() {
    return CustomTimeState();
  }
}

class CustomTimeState extends State<DatePickerDialog> {

  bool showDate = false;
  var chooseDateStr = '';

  @override
  Widget build(BuildContext context) {
    return Material(
      child: SizedBox(
        height: 475,
        child: Container(
          color: Colors.white,
          child: Column(
            children: <Widget>[
              _buildTitleBar(),
              _buildLine(),
              _buildDatePicker(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildTitleBar() {
    return Container(
      padding: EdgeInsets.only(top: 10, left: 15, bottom: 10, right: 15),
      child: Row(
        children: <Widget>[
          InkWell(
            child: Text(
              '取消',
              style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w300,
                  color: ColorRes.text_little_blue),
            ),
            onTap: () {
              AppRoute.pop(context);
            },
          ),
          Expanded(
            child: Center(
              child: Text(
                '选择日期',
                style: TextStyle(fontSize: 15, fontWeight: FontWeight.w300),
              ),
            ),
          ),
          InkWell(
            child: Text('确认',
                style: TextStyle(
                    fontSize: 14,
                    fontWeight: FontWeight.w300,
                    color: ColorRes.text_little_blue)),
            onTap: () {
              if(chooseDateStr==''){
                Toast.show('选择日期不能为空!', context);
                return ;
              }
              DateTime choose= DateUtils.strToDate(chooseDateStr);
              DateTime limitStart= DateUtils.strToDate('2014-01-01');
              if(choose.isBefore(limitStart)){
                Toast.show('起始日期不能早于2014-01-01', context);
                return ;
              }
              widget.onSelectedDate(chooseDateStr);
              FocusScope.of(context).unfocus();
              Navigator.pop(context);
            },
          )
        ],
      ),
    );
  }

  Widget _buildLine() {
    return Gaps.line;
  }

  Widget _buildDatePicker() {
    return DatePickerWidget(onSetter: (value) {
      showDate = false;
      chooseDateStr = value;
    });
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113

实际使用时候,使用showCupertinoModalPopup组件展示出来即可,如下所示。

showCalendarSheet(){
   showCupertinoModalPopup(
      context: context,
      builder: (BuildContext context) {
        return DatePickerDialog(onSelectedDate: (value){
           
        },
        );
      },
    );
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/145242
推荐阅读
相关标签
  

闽ICP备14008679号