首页 > 其他分享 >在flutter中用flutter_datetime_picker只选择年月,或只选择年,以及选择日期

在flutter中用flutter_datetime_picker只选择年月,或只选择年,以及选择日期

时间:2024-08-27 14:40:19浏览次数:12  
标签:picker widget locale final 选择 theme context flutter pickerModel

flutter_datetime_picker组件没有配置只选择年或者月的,只能选择日期或者时间,现重新修改组件支持此功能

效果如下:只选择年月

只选择年

 日期就不用展示了,组件自己就有

导入包flutter_datetime_picker: 1.5.1

 修改组件的文件

 修改后的flutter_datetime_picker.dart代码

library flutter_datetime_picker;

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/src/datetime_picker_theme.dart' as example;
import 'package:flutter_datetime_picker/src/date_model.dart';
import 'package:flutter_datetime_picker/src/i18n_model.dart';

export 'package:flutter_datetime_picker/src/datetime_picker_theme.dart';
export 'package:flutter_datetime_picker/src/date_model.dart';
export 'package:flutter_datetime_picker/src/i18n_model.dart';

typedef DateChangedCallback(DateTime time);
typedef DateCancelledCallback();
typedef String? StringAtIndexCallBack(int index);

class DatePicker {
  ///
  /// Display date picker bottom sheet.
  ///
  static Future<DateTime?> showDatePicker(BuildContext context, {
    bool showTitleActions: true,
    bool isShowDay: true,
    bool isShowMonth: true,
    DateTime? minTime,
    DateTime? maxTime,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    DateCancelledCallback? onCancel,
    locale: LocaleType.en,
    DateTime? currentTime,
    example.DatePickerTheme? theme,
  }) async {
    return await Navigator.push(
      context,
      _DatePickerRoute(
        showTitleActions: showTitleActions,
        onChanged: onChanged,
        onConfirm: onConfirm,
        onCancel: onCancel,
        locale: locale,
        theme: theme,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
        barrierLabel:
        MaterialLocalizations
            .of(context)
            .modalBarrierDismissLabel,
        pickerModel: DatePickerModel(
          currentTime: currentTime,
          maxTime: maxTime,
          minTime: minTime,
          locale: locale,
        ),
      ),
    );
  }

  ///
  /// Display time picker bottom sheet.
  ///
  static Future<DateTime?> showTimePicker(BuildContext context, {
    bool showTitleActions: true,
    bool isShowDay: true,
    bool isShowMonth: true,
    bool showSecondsColumn: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    DateCancelledCallback? onCancel,
    locale: LocaleType.en,
    DateTime? currentTime,
    example.DatePickerTheme? theme,
  }) async {
    return await Navigator.push(
      context,
      _DatePickerRoute(
        showTitleActions: showTitleActions,
        onChanged: onChanged,
        onConfirm: onConfirm,
        onCancel: onCancel,
        locale: locale,
        theme: theme,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
        barrierLabel:
        MaterialLocalizations
            .of(context)
            .modalBarrierDismissLabel,
        pickerModel: TimePickerModel(
          currentTime: currentTime,
          locale: locale,
          showSecondsColumn: showSecondsColumn,
        ),
      ),
    );
  }

  ///
  /// Display time picker bottom sheet with AM/PM.
  ///
  static Future<DateTime?> showTime12hPicker(BuildContext context, {
    bool showTitleActions: true,
    bool isShowDay: true,
    bool isShowMonth: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    DateCancelledCallback? onCancel,
    locale: LocaleType.en,
    DateTime? currentTime,
    example.DatePickerTheme? theme,
  }) async {
    return await Navigator.push(
      context,
      _DatePickerRoute(
        showTitleActions: showTitleActions,
        onChanged: onChanged,
        onConfirm: onConfirm,
        onCancel: onCancel,
        locale: locale,
        theme: theme,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
        barrierLabel:
        MaterialLocalizations
            .of(context)
            .modalBarrierDismissLabel,
        pickerModel: Time12hPickerModel(
          currentTime: currentTime,
          locale: locale,
        ),
      ),
    );
  }

  ///
  /// Display date&time picker bottom sheet.
  ///
  static Future<DateTime?> showDateTimePicker(BuildContext context, {
    bool showTitleActions: true,
    bool isShowDay: true,
    bool isShowMonth: true,
    DateTime? minTime,
    DateTime? maxTime,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    DateCancelledCallback? onCancel,
    locale: LocaleType.en,
    DateTime? currentTime,
    example.DatePickerTheme? theme,
  }) async {
    return await Navigator.push(
      context,
      _DatePickerRoute(
        showTitleActions: showTitleActions,
        onChanged: onChanged,
        onConfirm: onConfirm,
        onCancel: onCancel,
        locale: locale,
        theme: theme,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
        barrierLabel:
        MaterialLocalizations
            .of(context)
            .modalBarrierDismissLabel,
        pickerModel: DateTimePickerModel(
          currentTime: currentTime,
          minTime: minTime,
          maxTime: maxTime,
          locale: locale,
        ),
      ),
    );
  }

  ///
  /// Display date picker bottom sheet witch custom picker model.
  ///
  static Future<DateTime?> showPicker(BuildContext context, {
    bool showTitleActions: true,
    bool isShowDay: true,
    bool isShowMonth: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    DateCancelledCallback? onCancel,
    locale: LocaleType.en,
    BasePickerModel? pickerModel,
    example.DatePickerTheme? theme,
  }) async {
    return await Navigator.push(
      context,
      _DatePickerRoute(
        showTitleActions: showTitleActions,
        onChanged: onChanged,
        onConfirm: onConfirm,
        onCancel: onCancel,
        locale: locale,
        theme: theme,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
        barrierLabel:
        MaterialLocalizations
            .of(context)
            .modalBarrierDismissLabel,
        pickerModel: pickerModel,
      ),
    );
  }
}

class _DatePickerRoute<T> extends PopupRoute<T> {
  _DatePickerRoute({
    this.showTitleActions,
    this.onChanged,
    this.onConfirm,
    this.onCancel,
    example.DatePickerTheme? theme,
    this.barrierLabel,
    this.locale,
    this.isShowDay,
    this.isShowMonth,
    RouteSettings? settings,
    BasePickerModel? pickerModel,
  })
      : this.pickerModel = pickerModel ?? DatePickerModel(),
        this.theme = theme ?? example.DatePickerTheme(),
        super(settings: settings);

  final bool? showTitleActions;
  final DateChangedCallback? onChanged;
  final DateChangedCallback? onConfirm;
  final DateCancelledCallback? onCancel;
  final LocaleType? locale;
  final bool? isShowDay;
  final bool? isShowMonth;
  final example.DatePickerTheme theme;
  final BasePickerModel pickerModel;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 200);

  @override
  bool get barrierDismissible => true;

  @override
  final String? barrierLabel;

  @override
  Color get barrierColor => Colors.black54;

  AnimationController? _animationController;

  @override
  AnimationController createAnimationController() {
    assert(_animationController == null);
    _animationController =
        BottomSheet.createAnimationController(navigator!.overlay!);
    return _animationController!;
  }

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    Widget bottomSheet = MediaQuery.removePadding(
      context: context,
      removeTop: true,
      child: _DatePickerComponent(
        onChanged: onChanged,
        locale: this.locale,
        route: this,
        pickerModel: pickerModel,
        isShowDay: isShowDay,
        isShowMonth: isShowMonth,
      ),
    );
    return InheritedTheme.captureAll(context, bottomSheet);
  }
}

class _DatePickerComponent extends StatefulWidget {
  _DatePickerComponent({
    Key? key,
    required this.route,
    required this.pickerModel,
    this.isShowDay,
    this.isShowMonth,
    this.onChanged,
    this.locale,
  }) : super(key: key);

  final DateChangedCallback? onChanged;

  final _DatePickerRoute route;

  final LocaleType? locale;

  final BasePickerModel pickerModel;
  bool? isShowDay;
  bool? isShowMonth;

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

class _DatePickerState extends State<_DatePickerComponent> {
  late FixedExtentScrollController leftScrollCtrl,
      middleScrollCtrl,
      rightScrollCtrl;

  @override
  void initState() {
    super.initState();
    refreshScrollOffset();
  }

  void refreshScrollOffset() {
//    print('refreshScrollOffset ${widget.pickerModel.currentRightIndex()}');
    leftScrollCtrl = FixedExtentScrollController(
        initialItem: widget.pickerModel.currentLeftIndex());
    middleScrollCtrl = FixedExtentScrollController(
        initialItem: widget.pickerModel.currentMiddleIndex());
    rightScrollCtrl = FixedExtentScrollController(
        initialItem: widget.pickerModel.currentRightIndex());
  }

  @override
  Widget build(BuildContext context) {
    example.DatePickerTheme theme = widget.route.theme;
    return GestureDetector(
      child: AnimatedBuilder(
        animation: widget.route.animation!,
        builder: (BuildContext context, Widget? child) {
          final double bottomPadding = MediaQuery
              .of(context)
              .padding
              .bottom;
          return ClipRect(
            child: CustomSingleChildLayout(
              delegate: _BottomPickerLayout(
                widget.route.animation!.value,
                theme,
                showTitleActions: widget.route.showTitleActions!,
                bottomPadding: bottomPadding,
              ),
              child: GestureDetector(
                child: Material(
                  color: theme.backgroundColor ?? Colors.white,
                  child: _renderPickerView(theme),
                ),
              ),
            ),
          );
        },
      ),
    );
  }

  void _notifyDateChanged() {
    if (widget.onChanged != null) {
      widget.onChanged!(widget.pickerModel.finalTime()!);
    }
  }

  Widget _renderPickerView(example.DatePickerTheme theme) {
    Widget itemView = _renderItemView(theme);
    if (widget.route.showTitleActions == true) {
      return Column(
        children: <Widget>[
          _renderTitleActionsView(theme),
          itemView,
        ],
      );
    }
    return itemView;
  }

  Widget _renderColumnView(ValueKey key,
      example.DatePickerTheme theme,
      StringAtIndexCallBack stringAtIndexCB,
      ScrollController scrollController,
      int layoutProportion,
      ValueChanged<int> selectedChangedWhenScrolling,
      ValueChanged<int> selectedChangedWhenScrollEnd,) {
    return Expanded(
      flex: layoutProportion,
      child: Container(
        padding: EdgeInsets.all(8.0),
        height: theme.containerHeight,
        decoration: BoxDecoration(color: theme.backgroundColor),
        child: NotificationListener(
          onNotification: (ScrollNotification notification) {
            if (notification.depth == 0 &&
                notification is ScrollEndNotification &&
                notification.metrics is FixedExtentMetrics) {
              final FixedExtentMetrics metrics =
              notification.metrics as FixedExtentMetrics;
              final int currentItemIndex = metrics.itemIndex;
              selectedChangedWhenScrollEnd(currentItemIndex);
            }
            return false;
          },
          child: CupertinoPicker.builder(
            key: key,
            backgroundColor: theme.backgroundColor,
            scrollController: scrollController as FixedExtentScrollController,
            itemExtent: theme.itemHeight,
            onSelectedItemChanged: (int index) {
              selectedChangedWhenScrolling(index);
            },
            useMagnifier: true,
            itemBuilder: (BuildContext context, int index) {
              final content = stringAtIndexCB(index);
              if (content == null) {
                return null;
              }
              return Container(
                height: theme.itemHeight,
                alignment: Alignment.center,
                child: Text(
                  content,
                  style: theme.itemStyle,
                  textAlign: TextAlign.start,
                ),
              );
            },
          ),
        ),
      ),
    );
  }

  Widget _renderItemView(example.DatePickerTheme theme) {
    return Container(
      color: theme.backgroundColor,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(
            child: widget.pickerModel.layoutProportions()[0] > 0
                ? _renderColumnView(
                ValueKey(widget.pickerModel.currentLeftIndex()),
                theme,
                widget.pickerModel.leftStringAtIndex,
                leftScrollCtrl,
                widget.pickerModel.layoutProportions()[0], (index) {
              widget.pickerModel.setLeftIndex(index);
            }, (index) {
              setState(() {
                refreshScrollOffset();
                _notifyDateChanged();
              });
            })
                : null,
          ),
          Text(
            widget.pickerModel.leftDivider(),
            style: theme.itemStyle,
          ),
          widget.isShowMonth ?? true
              ? Container(
            child: widget.pickerModel.layoutProportions()[1] > 0
                ? _renderColumnView(
                ValueKey(widget.pickerModel.currentLeftIndex()),
                theme,
                widget.pickerModel.middleStringAtIndex,
                middleScrollCtrl,
                widget.pickerModel.layoutProportions()[1], (index) {
              widget.pickerModel.setMiddleIndex(index);
            }, (index) {
              setState(() {
                refreshScrollOffset();
                _notifyDateChanged();
              });
            })
                : null,
          ) :
          Container(),
          Text(
            widget.pickerModel.rightDivider(),
            style: theme.itemStyle,
          ),
          widget.isShowDay ?? true
              ? Container(
            child: widget.pickerModel.layoutProportions()[2] > 0
                ? _renderColumnView(
                ValueKey(widget.pickerModel.currentMiddleIndex() * 100 +
                    widget.pickerModel.currentLeftIndex()),
                theme,
                widget.pickerModel.rightStringAtIndex,
                rightScrollCtrl,
                widget.pickerModel.layoutProportions()[2], (index) {
              widget.pickerModel.setRightIndex(index);
            }, (index) {
              setState(() {
                refreshScrollOffset();
                _notifyDateChanged();
              });
            })
                : null,
          ) :
          Container(),
        ],
      ),
    );
  }

  // Title View
  Widget _renderTitleActionsView(example.DatePickerTheme theme) {
    final done = _localeDone();
    final cancel = _localeCancel();

    return Container(
      height: theme.titleHeight,
      decoration: BoxDecoration(
        color: theme.headerColor ?? theme.backgroundColor,
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(
            height: theme.titleHeight,
            child: CupertinoButton(
              pressedOpacity: 0.3,
              padding: EdgeInsets.only(left: 16, top: 0),
              child: Text(
                '$cancel',
                style: theme.cancelStyle,
              ),
              onPressed: () {
                Navigator.pop(context);
                if (widget.route.onCancel != null) {
                  widget.route.onCancel!();
                }
              },
            ),
          ),
          Container(
            height: theme.titleHeight,
            child: CupertinoButton(
              pressedOpacity: 0.3,
              padding: EdgeInsets.only(right: 16, top: 0),
              child: Text(
                '$done',
                style: theme.doneStyle,
              ),
              onPressed: () {
                Navigator.pop(context, widget.pickerModel.finalTime());
                if (widget.route.onConfirm != null) {
                  widget.route.onConfirm!(widget.pickerModel.finalTime()!);
                }
              },
            ),
          ),
        ],
      ),
    );
  }

  String _localeDone() {
    return i18nObjInLocale(widget.locale)['done'] as String;
  }

  String _localeCancel() {
    return i18nObjInLocale(widget.locale)['cancel'] as String;
  }
}

class _BottomPickerLayout extends SingleChildLayoutDelegate {
  _BottomPickerLayout(this.progress,
      this.theme, {
        this.itemCount,
        this.showTitleActions,
        this.bottomPadding = 0,
      });

  final double progress;
  final int? itemCount;
  final bool? showTitleActions;
  final example.DatePickerTheme theme;
  final double bottomPadding;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    double maxHeight = theme.containerHeight;
    if (showTitleActions == true) {
      maxHeight += theme.titleHeight;
    }

    return BoxConstraints(
      minWidth: constraints.maxWidth,
      maxWidth: constraints.maxWidth,
      minHeight: 0.0,
      maxHeight: maxHeight + bottomPadding,
    );
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    final height = size.height - childSize.height * progress;
    return Offset(0.0, height);
  }

  @override
  bool shouldRelayout(_BottomPickerLayout oldDelegate) {
    return progress != oldDelegate.progress;
  }
}
View Code

使用:

  void showDatePicker() {
    DatePicker.showDatePicker(
      context,
      showTitleActions: true,
      isShowDay: false,//是否要选择日
      isShowMonth: false,//是否要选择月
      minTime: DateTime(1996, 3, 5),
      maxTime: DateTime(2099, 6, 7),
      onChanged: (date) {
        print('change $date');
      },
      onConfirm: (date) {
        print('confirm $date');
      },
      currentTime: DateTime.now(),
      locale: LocaleType.zh,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ElevatedButton(
          onPressed: showDatePicker,
          child: Text('Select Date'),
        ),
      ],
    );
  }

 

标签:picker,widget,locale,final,选择,theme,context,flutter,pickerModel
From: https://www.cnblogs.com/heyiping/p/18382624

相关文章

  • VBA学习(60):补充:Excel VBA 选择输入/TreeView控件/在工作表中如何顺利使用TreeView控
    上一篇文章我们分享了一例通过TreeView控件,实现会计科目的选择输入的方法,(ExcelVBA选择输入/TreeView控件):然而,当今天我打开它准备发送给索要示例文件的小伙伴的时候,咦,这是什么鬼?再进入设计模式:TreeView1这个控件,它在啊在代码窗口查看:名称怎么变成了TreeView41?难......
  • flutter使用flutter_datetime_picker时导入冲突 'DatePickerTheme' is imported from
    安装flutter_datetime_picker后运行项目出现下面的报错 在ChipsInput小部件中,您使用了两个相互冲突的导入。在调用this.theme=theme??DatePickerTheme()时会发生冲突,因为它不知道使用哪个导入,因为它们具有相同的名称。您需要删除import'package:flutter/src/material/date......
  • 滴滴开源 Flutter 混合开发框架 Unify
    滴滴开源Flutter混合开发框架Unify来源:OSCHINA编辑: 局2024-08-1612:24:00 1滴滴近日开源了自研Unify框架,旨在解决大规模跨端落地场景下,Flutter与原生模块之间的通信问题。Unify通过平台无关的模块抽象、灵活的实现注入、自动代码生成等特性,为开发者提......
  • auto_size_text 自动调整文本大小以适应其容器的 Flutter 插件
    依赖auto_size_text:^3.0.0//自动调整文本大小例子classAutoSizeRichTextExampleextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnCenter(child:Container(width:double.infinity,child:AutoSi......
  • 青少年等级考试该怎么选择
    倒计时15天,9月青少年等级考试报名即将截止 青少年等级考试2024年9月一报名倒计时第15天 报名网址:www.qceit.org.cn报名时间:2024年7月8日-9月10日16:00考生注册、登录后填报信息并完成缴费视为报名成功。注意事项: 1.报名结束前,考生因个人原因可申请退考,全额退......
  • 特征选择
    参考:https://blog.csdn.net/Datawhale/article/details/120582526https://zhuanlan.zhihu.com/p/74198735特征选择目录特征选择一般流程三大类方法过滤法1.单变量2.多变量2.1连续型vs连续型(1)Pearson相关系数(2)斯皮尔曼相关系数2.2连续型vs类别型(1)方差分析(2)肯德......
  • Python数据结构精要:选择与应用
    数据结构是计算机科学中一个重要的概念,它涉及到如何组织和存储数据以便于高效地访问和修改。Python作为一种高级编程语言,提供了多种内置的数据结构来满足不同的需求。本文旨在介绍Python中常见的几种数据结构,并通过实例来说明它们的使用场景和优缺点。Python中的基本数......
  • 为什么这么多人选择海运系统?它适用于什么场景?
    海运系统,为海运专线提供了卓越的解决方案。该系统不仅涵盖派送对接、入库开单与打板操作、客户管理、财务对账等核心功能,还支持客户物流追踪、验货查询、包裹认领等一站式服务。同时,它还提供在线充值、转账汇款、订单付款及交易明细查询等便捷功能。即便是复杂的财务管理环节......
  • 一文告诉你如果选择好的货代海运系统
    众所周知,海运是目前跨境电商物流中主流的干线运输手段之一,和空、铁、路运相比,海运的成本更低、运输量更大、通行能力也更强。但由于海运途中的不可控因素极大,流程环节多且长,因此也需要管理系统的辅助以提供更好的服务支持。那么应该选择好的货代海运系统呐?我们先来看看货代海......
  • 10款主流图纸加密软件强力推荐|2024年图纸加密软件最佳选择!
    在现代商业环境中,企业图纸作为重要的知识产权和核心竞争力,一旦泄露可能会对企业造成严重的经济损失和竞争劣势。随着信息安全需求的不断提高,图纸加密软件的应用变得尤为重要。图纸加密不仅能够保护企业的技术机密,还能有效防止内部人员的恶意泄密。1.安秉图纸加密软件安秉图......