导入包flutter_datetime_picker: 1.5.0
封装
import 'package:atui/jade/utils/JadeColors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';class ATuiDateTimePickerDialog {static Future<DateTime> showDatePicker(BuildContext context, {bool showTitleActions: true,bool isShowDay: true,DateTime minTime,DateTime maxTime,DateChangedCallback onChanged,DateChangedCallback onConfirm,Function onCustomDateConfirm,DateCancelledCallback onCancel,locale: LocaleType.en,DateTime currentTime,DatePickerTheme theme,}) async {return await Navigator.push(context,_DatePickerRoute(showTitleActions: showTitleActions,onChanged: onChanged,onConfirm: onConfirm,onCustomDateConfirm: onCustomDateConfirm,onCancel: onCancel,locale: locale,theme: theme,isShowDay: isShowDay,barrierLabel:MaterialLocalizations.of(context).modalBarrierDismissLabel,pickerModel: DatePickerModel(currentTime: currentTime,maxTime: maxTime,minTime: minTime,locale: locale,),),);}
}class _DatePickerRoute<T> extends PopupRoute<T> {_DatePickerRoute({this.showTitleActions,this.onChanged,this.onConfirm,this.onCustomDateConfirm,this.onCancel,theme,this.barrierLabel,this.locale,this.isShowDay,RouteSettings settings,pickerModel,}) : this.pickerModel = pickerModel ?? DatePickerModel(),this.theme = theme ?? DatePickerTheme(),super(settings: settings);final bool showTitleActions;final DateChangedCallback onChanged;final DateChangedCallback onConfirm;final Function onCustomDateConfirm;final DateCancelledCallback onCancel;final DatePickerTheme theme;final LocaleType locale;final BasePickerModel pickerModel;final bool isShowDay;Duration get transitionDuration => const Duration(milliseconds: 200); bool get barrierDismissible => true;final String barrierLabel;Color get barrierColor => Colors.black54;AnimationController _animationController;AnimationController createAnimationController() {assert(_animationController == null);_animationController =BottomSheet.createAnimationController(navigator.overlay);return _animationController;}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,),);return InheritedTheme.captureAll(context, bottomSheet);}
}class _DatePickerComponent extends StatefulWidget {_DatePickerComponent({Key key, this.route,this.onChanged,this.locale,this.pickerModel,this.isShowDay}): super(key: key);final DateChangedCallback onChanged;final _DatePickerRoute route;final LocaleType locale;final BasePickerModel pickerModel;bool isShowDay;State<StatefulWidget> createState() {return _DatePickerState();}
}class _DatePickerState extends State<_DatePickerComponent> {FixedExtentScrollController leftScrollCtrl, middleScrollCtrl, rightScrollCtrl;List<String> _btnTitleList = ['按日','按月','自定义'];int _selectPosition = 0;bool _isCustomTime = false;String _startDate;String _endDate = '结束时间';int _customDateType = 1; //1:开始时间 2:结束时间void initState() {super.initState();refreshScrollOffset();_startDate = '${widget.pickerModel.finalTime().year}/${widget.pickerModel.finalTime().month}/${widget.pickerModel.finalTime().day}';}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());}Widget build(BuildContext context) {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,shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(15.0),topRight: Radius.circular(10.0)), // 设置圆角半径),child: _renderPickerView(theme)),),),);},),);}void _notifyDateChanged() {if (widget.onChanged != null) {widget.onChanged(widget.pickerModel.finalTime());}String _date = '${widget.pickerModel.finalTime().year}/${widget.pickerModel.finalTime().month}/${widget.pickerModel.finalTime().day}';if(_customDateType == 1){_startDate = _date;}else if(_customDateType == 2){_endDate = _date;}}Widget _renderPickerView(DatePickerTheme theme) {Widget itemView = _renderItemView(theme);return Column(children: <Widget>[if (widget.route.showTitleActions)_renderTitleActionsView(theme),_switchBtnView(),itemView,],);}Widget _renderColumnView(ValueKey key,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 ?? Colors.white),child: NotificationListener(onNotification: (ScrollNotification notification) {if (notification.depth == 0 &&selectedChangedWhenScrollEnd != null &¬ification is ScrollEndNotification &¬ification.metrics is FixedExtentMetrics) {final FixedExtentMetrics metrics = notification.metrics;final int currentItemIndex = metrics.itemIndex;selectedChangedWhenScrollEnd(currentItemIndex);}return false;},child: CupertinoPicker.builder(key: key,backgroundColor: theme.backgroundColor ?? Colors.white,scrollController: scrollController,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(DatePickerTheme theme) {return Container(color: theme.backgroundColor ?? Colors.white,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,),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,),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 ViewWidget _renderTitleActionsView(DatePickerTheme theme) {final done = _localeDone();final cancel = _localeCancel();return Container(height: theme.titleHeight,decoration: BoxDecoration(color: theme.headerColor ?? theme.backgroundColor ?? Colors.white,borderRadius: BorderRadius.only(topLeft: Radius.circular(15.0),topRight: Radius.circular(15.0))),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) {if(!_isCustomTime){widget.route.onConfirm(widget.pickerModel.finalTime());}else{widget.route.onCustomDateConfirm(_startDate,_endDate);}}},),),],),);}String _localeDone() {return i18nObjInLocale(widget.locale)['done'];}String _localeCancel() {return i18nObjInLocale(widget.locale)['cancel'];}//切换按钮Widget _switchBtnView(){return Container(height: 120.w,padding: EdgeInsets.symmetric(horizontal: 30.w),child: Column(children: [Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [Wrap(alignment: WrapAlignment.start,direction: Axis.horizontal,spacing: 30.w,textDirection: TextDirection.ltr,children: List.generate(_btnTitleList.length, (index) {return GestureDetector(child: Container(padding: EdgeInsets.only(left: 24.w,right: 24.w,top: 10.w,bottom: 12.w),decoration: BoxDecoration(color: _selectPosition == index ? JadeColors.yellow : JadeColors.lightGrey,borderRadius: BorderRadius.all(Radius.circular(20)),),child: Text(_btnTitleList[index],style: TextStyle(fontSize: 28.sp,color: _selectPosition == index ? JadeColors.grey_2 : JadeColors.grey),),),onTap: (){setState(() {_selectPosition = index;if(_selectPosition == 0){widget.isShowDay = true;_isCustomTime = false;}else if(_selectPosition == 1){widget.isShowDay = false;_isCustomTime = false;}else if(_selectPosition == 2){widget.isShowDay = true;_isCustomTime = true;}});},);})),GestureDetector(child: Container(padding: EdgeInsets.only(left: 20.w,right: 20.w,top: 10.w,bottom: 10.w),decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(20),border: Border.all(width: 1.w,color: JadeColors.grey_2)),child: Text('清除筛选',style: TextStyle(fontSize: 28.sp,color: JadeColors.grey_2),),),)],),_customDataSelectView()],),);}_customDataSelectView(){return _isCustomTime?Container(margin: EdgeInsets.only(top: 15.w),child: Row(mainAxisAlignment: MainAxisAlignment.center,children: [GestureDetector(child: Column(children: [IntrinsicWidth(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text("$_startDate",style: TextStyle(overflow: TextOverflow.fade, color: _customDateType == 1?JadeColors.red_6 : JadeColors.grey_7, fontSize: 30.sp),),Container(margin: EdgeInsets.only(top: 1.h),height: 1,color: _customDateType == 1?JadeColors.red_6 : JadeColors.grey_7,)],),),]),onTap: () {setState(() {_customDateType = 1;});}),Container(width: 30.w, height: 1, color: JadeColors.grey_7, margin: EdgeInsets.symmetric(horizontal: 40.w)),GestureDetector(child: Column(children: [IntrinsicWidth(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text("$_endDate",style: TextStyle(overflow: TextOverflow.fade, color: _customDateType == 2?JadeColors.red_6 : JadeColors.grey_7, fontSize: 30.sp),),Container(margin: EdgeInsets.only(top: 1.h),height: 1,color: _customDateType == 2?JadeColors.red_6 : JadeColors.grey_7,)],),),]),onTap: () {setState(() {_customDateType = 2;});})],),):Container();}}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 DatePickerTheme theme;final double bottomPadding;BoxConstraints getConstraintsForChild(BoxConstraints constraints) {double maxHeight = theme.containerHeight;if (showTitleActions) {maxHeight += theme.titleHeight + 120.w;//增加actionTitle布局(取消、确定)时和切换按钮的布局时要在当前的布局高度上再加上去}return BoxConstraints(minWidth: constraints.maxWidth,maxWidth: constraints.maxWidth,minHeight: 0.0,maxHeight: maxHeight + bottomPadding,);}Offset getPositionForChild(Size size, Size childSize) {final height = size.height - childSize.height * progress;return Offset(0.0, height);} bool shouldRelayout(_BottomPickerLayout oldDelegate) {return progress != oldDelegate.progress;}
}
引用
_dateFilter() async {LocaleType localeType;await ATuiSharedPreferences.getStorage("localType").then((value) {if (value == "zh") {localeType = LocaleType.zh;} else if (value == "en") {localeType = LocaleType.en;}});ATuiDateTimePickerDialog.showDatePicker(context,//isShowDay: false,locale: localeType ?? LocaleType.zh,theme: DatePickerTheme(cancelStyle: TextStyle(fontSize: 30.sp,color: JadeColors.grey_2),doneStyle: TextStyle(fontSize: 30.sp,color: JadeColors.grey_2,fontWeight: FontWeight.w600)),onConfirm: (datetime) async {String newDate = '${datetime.year}-${datetime.month}-${datetime.day}';newDate += datetime.month < 10? '0${datetime.month}': datetime.month.toString();print('非自定义时点击确定按钮= $newDate');},onCustomDateConfirm: (startDatetime,endDatetime) async {print('自定义时点击确定按钮');print('startDatetime= $startDatetime');print('endDatetime= $endDatetime');},onChanged: (datetime) {print('onChanged dateTime: ${datetime}');},);}