flutter 时间选择器 年月日季度周 (在第三方基础上修改的)
在第三方flutter_picker 基础上修改了时间选择器 年月日季度周 选择器
datePicker.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:semf_flutter/generated/i18n.dart'; import 'dart:async'; const bool __printDebug = false; /// Picker selected callback. typedef PickerSelectedCallback = void Function( Picker picker, int index, List<int> selecteds); /// Picker confirm callback. typedef PickerConfirmCallback = void Function( Picker picker, List<int> selecteds); /// Picker class Picker { static const double DefaultTextSize = 20.0; /// Index of currently selected items List<int> selecteds; /// Picker adapter, Used to provide data and generate widgets final PickerAdapter adapter; /// insert separator before picker columns final List<PickerDelimiter> delimiter; final VoidCallback onCancel; final PickerSelectedCallback onSelect; final PickerConfirmCallback onConfirm; /// When the previous level selection changes, scroll the child to the first item. final changeToFirst; /// Specify flex for each column final List<int> columnFlex; final Widget title; final Widget cancel; final Widget confirm; final String cancelText; final String confirmText; final double height; /// Height of list item final double itemExtent; final TextStyle textStyle, cancelTextStyle, confirmTextStyle, selectedTextStyle; final TextAlign textAlign; /// Text scaling factor final double textScaleFactor; final EdgeInsetsGeometry columnPadding; final Color backgroundColor, headercolor, containerColor; /// Hide head final bool hideHeader; /// Show pickers in reversed order final bool reversedOrder; /// List item loop final bool looping; /// Delay generation for smoother animation, This is the number of milliseconds to wait. It is recommended to > = 200 final int smooth; final Widget footer; final Decoration headerDecoration; final double magnification; final double diameterRatio; final double squeeze; Widget _widget; PickerWidgetState _state; Picker( {this.adapter, this.delimiter, this.selecteds, this.height = 150.0, this.itemExtent = 28.0, this.columnPadding, this.textStyle, this.cancelTextStyle, this.confirmTextStyle, this.selectedTextStyle, this.textAlign = TextAlign.start, this.textScaleFactor, this.title, this.cancel, this.confirm, this.cancelText, this.confirmText, this.backgroundColor = Colors.white, this.containerColor, this.headercolor, this.changeToFirst = false, this.hideHeader = false, this.looping = false, this.reversedOrder = false, this.headerDecoration, this.columnFlex, this.footer, this.smooth, this.magnification = 1.0, this.diameterRatio = 1.1, this.squeeze = 1.45, this.onCancel, this.onSelect, this.onConfirm}) : assert(adapter != null); Widget get widget => _widget; PickerWidgetState get state => _state; int _maxLevel = 1; /// 生成picker控件 /// Build picker control Widget makePicker([ThemeData themeData, bool isModal = false]) { _maxLevel = adapter.maxLevel; adapter.picker = this; adapter.initSelects(); _widget = _PickerWidget(picker: this, themeData: themeData, isModal: isModal); return _widget; } /// show picker void show(ScaffoldState state, [ThemeData themeData]) { state.showBottomSheet((BuildContext context) { return makePicker(themeData); }); } /// 获取当前选择的值 /// Get the value of the current selection List getSelectedValues() { return adapter.getSelectedValues(); } /// 取消 void doCancel(BuildContext context) { if (onCancel != null) onCancel(); Navigator.of(context).pop<List<int>>(null); _widget = null; } /// 确定 void doConfirm(BuildContext context) { if (onConfirm != null) onConfirm(this, selecteds); Navigator.of(context).pop(); _widget = null; } /// 弹制更新指定列的内容 /// 当 onSelect 事件中,修改了当前列前面的列的内容时,可以调用此方法来更新显示 void updateColumn(int index, [bool all = false]) { if (all) { _state.update(); return; } adapter.setColumn(index - 1); _state._keys[index].currentState.update(); } } /// 分隔符 class PickerDelimiter { final Widget child; final int column; PickerDelimiter({this.child, this.column = 1}) : assert(child != null); } /// picker data list item class PickerItem<T> { /// 显示内容 final Widget text; /// 数据值 final T value; /// 子项 final List<PickerItem<T>> children; PickerItem({this.text, this.value, this.children}); } class _PickerWidget<T> extends StatefulWidget { final Picker picker; final ThemeData themeData; final bool isModal; _PickerWidget( {Key key, @required this.picker, @required this.themeData, this.isModal}) : super(key: key); @override PickerWidgetState createState() => PickerWidgetState<T>(picker: this.picker, themeData: this.themeData); } class PickerWidgetState<T> extends State<_PickerWidget> { final Picker picker; final ThemeData themeData; PickerWidgetState({Key key, @required this.picker, @required this.themeData}); ThemeData theme; final List<FixedExtentScrollController> scrollController = []; final List<GlobalKey<_StateViewState>> _keys = []; @override void initState() { super.initState(); theme = themeData; picker._state = this; picker.adapter.doShow(); if (scrollController.length == 0) { for (int i = 0; i < picker._maxLevel; i++) { scrollController .add(FixedExtentScrollController(initialItem: picker.selecteds[i])); _keys.add(GlobalKey(debugLabel: i.toString())); } } } void update() { setState(() {}); } // var ref = 0; @override Widget build(BuildContext context) { // print("picker build ${ref++}"); ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context); if (_wait && picker.smooth != null && picker.smooth > 0) { Future.delayed(Duration(milliseconds: picker.smooth), () { if (!_wait) return; setState(() { _wait = false; }); }); } else _wait = false; var _body = <Widget>[]; if (!picker.hideHeader) { _body.add(DecoratedBox( child: Row( children: _buildHeaderViews(), ), decoration: picker.headerDecoration ?? BoxDecoration( border: Border( top: BorderSide(color: theme.dividerColor, width: 0.5), bottom: BorderSide(color: theme.dividerColor, width: 0.5), ), color: picker.headercolor == null ? theme.bottomAppBarColor : picker.headercolor, ), )); } _body.add(_wait ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: _buildViews(), ) : AnimatedSwitcher( duration: Duration(milliseconds: 300), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: _buildViews(), ), )); if (picker.footer != null) _body.add(picker.footer); Widget v = Column( mainAxisSize: MainAxisSize.min, children: _body, ); if (widget.isModal != null && widget.isModal) { v = GestureDetector( onTap: () {}, child: v, ); } return v; } List<Widget> _headerItems; List<Widget> _buildHeaderViews() { if (_headerItems != null) return _headerItems; if (theme == null) theme = Theme.of(context); List<Widget> items = []; if (picker.cancel != null) { items.add(DefaultTextStyle( style: picker.cancelTextStyle ?? TextStyle( color: theme.accentColor, fontSize: Picker.DefaultTextSize), child: picker.cancel)); } else { String _cancelText = picker.cancelText ?? S.of(context).datePicker_Cancel; if (_cancelText != null || _cancelText != "") { items.add(FlatButton( onPressed: () { picker.doCancel(context); }, child: Text(_cancelText, overflow: TextOverflow.ellipsis, style: picker.cancelTextStyle ?? TextStyle( color: theme.accentColor, fontSize: Picker.DefaultTextSize)))); } } items.add(Expanded( child: Center( //alignment: Alignment.center, child: picker.title == null ? picker.title : DefaultTextStyle( style: TextStyle( fontSize: Picker.DefaultTextSize, color: theme.textTheme.title.color), child: picker.title), ))); if (picker.confirm != null) { items.add(DefaultTextStyle( style: picker.confirmTextStyle ?? TextStyle( color: theme.accentColor, fontSize: Picker.DefaultTextSize), child: picker.confirm)); } else { String _confirmText = picker.confirmText ?? S.of(context).datePicker_Confirm; if (_confirmText != null || _confirmText != "") { items.add(FlatButton( onPressed: () { picker.doConfirm(context); }, child: Text(_confirmText, overflow: TextOverflow.ellipsis, style: picker.confirmTextStyle ?? TextStyle( color: theme.accentColor, fontSize: Picker.DefaultTextSize)))); } } _headerItems = items; return items; } bool _changeing = false; bool _wait = true; final Map<int, int> lastData = {}; List<Widget> _buildViews() { if (__printDebug) print("_buildViews"); if (theme == null) theme = Theme.of(context); List<Widget> items = []; PickerAdapter adapter = picker.adapter; if (adapter != null) adapter.setColumn(-1); if (adapter != null && adapter.length > 0) { var _decoration = BoxDecoration( color: picker.containerColor == null ? theme.dialogBackgroundColor : picker.containerColor, ); for (int i = 0; i < picker._maxLevel; i++) { Widget view = Expanded( flex: adapter.getColumnFlex(i), child: Container( padding: picker.columnPadding, height: picker.height, decoration: _decoration, child: _wait ? null : _StateView( key: _keys[i], builder: (context) { adapter.setColumn(i - 1); var _length = adapter.length; var _view = CupertinoPicker.builder( backgroundColor: picker.backgroundColor, scrollController: scrollController[i], itemExtent: picker.itemExtent, // looping: picker.looping, magnification: picker.magnification, diameterRatio: picker.diameterRatio, squeeze: picker.squeeze, onSelectedItemChanged: (int _index) { if (__printDebug) print("onSelectedItemChanged"); var index = _index % _length; picker.selecteds[i] = index; updateScrollController(i); adapter.doSelect(i, index); if (picker.changeToFirst) { for (int j = i + 1; j < picker.selecteds.length; j++) { picker.selecteds[j] = 0; scrollController[j].jumpTo(0.0); } } if (picker.onSelect != null) picker.onSelect(picker, i, picker.selecteds); _keys[i].currentState.update(); if (adapter.isLinkage) { for (int j = i + 1; j < picker.selecteds.length; j++) { adapter.setColumn(j - 1); _keys[j].currentState.update(); } } }, itemBuilder: (context, index) { adapter.setColumn(i - 1); return adapter.buildItem(context, index % _length); }, childCount: picker.looping ? null : _length, ); if (!picker.changeToFirst && picker.selecteds[i] >= _length) { Timer(Duration(milliseconds: 100), () { if (__printDebug) print("timer last"); adapter.setColumn(i - 1); var _len = adapter.length; scrollController[i].jumpToItem( (_len < _length ? _len : _length) - 1); }); } return _view; }, ), ), ); items.add(view); } } if (picker.delimiter != null && !_wait) { for (int i = 0; i < picker.delimiter.length; i++) { var o = picker.delimiter[i]; if (o.child == null) continue; var item = Container(child: o.child, height: picker.height); if (o.column < 0) items.insert(0, item); else if (o.column >= items.length) items.add(item); else items.insert(o.column, item); } } if (picker.reversedOrder) return items.reversed.toList(); return items; } void updateScrollController(int i) { if (_changeing || !picker.adapter.isLinkage) return; _changeing = true; for (int j = 0; j < picker.selecteds.length; j++) { if (j != i) { if (scrollController[j].position.maxScrollExtent == null) continue; scrollController[j].position.notifyListeners(); } } _changeing = false; } } /// 选择器数据适配器 abstract class PickerAdapter<T> { Picker picker; int getLength(); int getMaxLevel(); void setColumn(int index); void initSelects(); Widget buildItem(BuildContext context, int index); Widget makeText(Widget child, String text, bool isSel) { return new Center( //alignment: Alignment.center, child: DefaultTextStyle( overflow: TextOverflow.ellipsis, maxLines: 1, textAlign: picker.textAlign, style: picker.textStyle ?? TextStyle( color: Colors.black87, fontSize: Picker.DefaultTextSize), child: child != null ? child : Text(text, textScaleFactor: picker.textScaleFactor, style: (isSel ? picker.selectedTextStyle : null)))); } Widget makeTextEx( Widget child, String text, Widget postfix, Widget suffix, bool isSel) { List<Widget> items = []; if (postfix != null) items.add(postfix); items.add( child ?? Text(text, style: (isSel ? picker.selectedTextStyle : null))); if (suffix != null) items.add(suffix); var _txtColor = Colors.black87; var _txtSize = Picker.DefaultTextSize; if (isSel && picker.selectedTextStyle != null) { if (picker.selectedTextStyle.color != null) _txtColor = picker.selectedTextStyle.color; if (picker.selectedTextStyle.fontSize != null) _txtSize = picker.selectedTextStyle.fontSize; } return new Center( //alignment: Alignment.center, child: DefaultTextStyle( overflow: TextOverflow.ellipsis, maxLines: 1, textAlign: picker.textAlign, style: picker.textStyle ?? TextStyle(color: _txtColor, fontSize: _txtSize), child: Wrap( children: items, ))); } String getText() { return getSelectedValues().toString(); } List<T> getSelectedValues() { return []; } void doShow() {} void doSelect(int column, int index) {} int getColumnFlex(int column) { if (picker.columnFlex != null && column < picker.columnFlex.length) return picker.columnFlex[column]; return 1; } int get maxLevel => getMaxLevel(); /// Content length of current column int get length => getLength(); String get text => getText(); // 是否联动,即后面的列受前面列数据影响 bool get isLinkage => getIsLinkage(); @override String toString() { return getText(); } bool getIsLinkage() { return true; } /// 通知适配器数据改变 void notifyDataChanged() { if (picker != null && picker.state != null) { picker.adapter.doShow(); picker.adapter.initSelects(); for (int j = 0; j < picker.selecteds.length; j++) picker.state.scrollController[j].jumpToItem(picker.selecteds[j]); } } } /// Picker DateTime Adapter Type class PickerDateTimeType { static const int kMDY = 0; // m, d, y static const int kHM = 1; // hh, mm static const int kHMS = 2; // hh, mm, ss static const int kHM_AP = 3; // hh, mm, ap(AM/PM) static const int kMDYHM = 4; // m, d, y, hh, mm static const int kMDYHM_AP = 5; // m, d, y, hh, mm, AM/PM static const int kMDYHMS = 6; // m, d, y, hh, mm, ss static const int kYMD = 7; // y, m, d static const int kYMDHM = 8; // y, m, d, hh, mm static const int kYMDHMS = 9; // y, m, d, hh, mm, ss static const int kYMD_AP_HM = 10; // y, m, d, ap, hh, mm static const int kYM = 11; // y, m static const int kDMY = 12; // d, m, y static const int kY = 13; // y static const int kYQ = 14; //y,Q static const int kYMWD = 15; //y,m,w,d } class DateTimePickerAdapter extends PickerAdapter<DateTime> { /// display type, ref: columnType final int type; /// Whether to display the month in numerical form.If true, months is not used. final bool isNumberMonth; /// custom months strings final List<String> months; /// Custom AM, PM strings final List<String> strAMPM; /// year begin...end. final int yearBegin, yearEnd; /// minimum datetime final DateTime minValue, maxValue; /// jump minutes, user could select time in intervals of 30min, 5mins, etc.... final int minuteInterval; /// Year, month, day suffix final String yearSuffix, monthSuffix, daySuffix, quarterSuffix, weekSuffix; /// use two-digit year, 2019, displayed as 19 final bool twoDigitYear; /// year 0, month 1, day 2, hour 3, minute 4, sec 5, am/pm 6, hour-ap: 7 final List<int> customColumnType; static const List<String> MonthsList_EN = const [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; static const List<String> MonthsList_EN_L = const [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; DateTimePickerAdapter({ Picker picker, this.type = 0, this.isNumberMonth = false, this.months = MonthsList_EN, this.strAMPM, this.yearBegin = 1900, this.yearEnd = 2100, this.value, this.minValue, this.maxValue, this.yearSuffix, this.monthSuffix, this.daySuffix, this.quarterSuffix, this.weekSuffix, this.minuteInterval, this.customColumnType, this.twoDigitYear = false, }) : assert(minuteInterval == null || (minuteInterval >= 1 && minuteInterval <= 30 && (60 % minuteInterval == 0))) { super.picker = picker; _yearBegin = yearBegin; if (minValue != null && minValue.year > _yearBegin) { _yearBegin = minValue.year; } } int _col = 0; int _colAP = -1; int _yearBegin = 0; /// Currently selected value DateTime value; // but it can improve the performance, so keep it. static const List<List<int>> lengths = const [ [12, 31, 0], [24, 60], [24, 60, 60], [12, 60, 2], [12, 31, 0, 24, 60], [12, 31, 0, 12, 60, 2], [12, 31, 0, 24, 60, 60], [0, 12, 31], [0, 12, 31, 24, 60], [0, 12, 31, 24, 60, 60], [0, 12, 31, 2, 12, 60], [0, 12], [31, 12, 0], [0], [0, 4], [0, 12, 52, 31], ]; static const Map<int, int> columnTypeLength = { 0: 0, 1: 12, 2: 31, 3: 24, 4: 60, 5: 60, 6: 2, 7: 12, 8: 4, 9: 52, }; /// year 0, month 1, day 2, hour 3, minute 4, sec 5, am/pm 6, hour-ap: 7 static const List<List<int>> columnType = const [ [1, 2, 0], [3, 4], [3, 4, 5], [7, 4, 6], [1, 2, 0, 3, 4], [1, 2, 0, 7, 4, 6], [1, 2, 0, 3, 4, 5], [0, 1, 2], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 6, 7, 4], [0, 1], [2, 1, 0], [0], [0, 8], [0, 1, 9, 2], ]; // static const List<int> leapYearMonths = const <int>[1, 3, 5, 7, 8, 10, 12]; // 获取当前列的类型 int getColumnType(int index) { if (customColumnType != null) return customColumnType[index]; List<int> items = columnType[type]; if (index >= items.length) return -1; return items[index]; } @override int getLength() { int v = customColumnType == null ? lengths[type][_col] : columnTypeLength[customColumnType[_col]]; if (v == 0) { //年 int ye = yearEnd; if (maxValue != null) ye = maxValue.year; return ye - _yearBegin + 1; } //日 if (v == 31) return _calcDateCount(value.year, value.month); if (minuteInterval != null && minuteInterval > 1) { int _type = getColumnType(_col); if (_type == 4) { return v ~/ minuteInterval; } } //周,如果当年的12月31是周四,则当年有53周 (国际规定是周四为一周的第一天) if (v == 52) { DateTime date = DateTime.utc(value.year, 12, 31); if (date.weekday == DateTime.thursday) { return 53; } } return v; } @override int getMaxLevel() { return customColumnType == null ? lengths[type].length : customColumnType.length; } @override void setColumn(int index) { //print("setColumn index: $index"); _col = index + 1; if (_col < 0) _col = 0; } @override void initSelects() { if (value == null) value = DateTime.now(); _colAP = _getAPColIndex(); int _maxLevel = getMaxLevel(); if (picker.selecteds == null || picker.selecteds.length == 0) { if (picker.selecteds == null) picker.selecteds = List<int>(); for (int i = 0; i < _maxLevel; i++) picker.selecteds.add(0); } } @override Widget buildItem(BuildContext context, int index) { String _text = ""; int colType = getColumnType(_col); switch (colType) { case 0: if (twoDigitYear != null && twoDigitYear) { _text = "${_yearBegin + index}"; var _l = _text.length; _text = "${_text.substring(_l - (_l - 2), _l)}${_checkStr(yearSuffix)}"; } else _text = "${_yearBegin + index}${_checkStr(yearSuffix)}"; break; case 1: if (isNumberMonth) { _text = "${intToStr(index + 1)}${_checkStr(monthSuffix)}"; } else { if (months != null) _text = "${intToStr(int.parse(months[index]))}"; else { // List _months = // PickerLocalizations // .of(context) // .months ?? MonthsList_EN; List _months = MonthsList_EN; _text = "${intToStr(_months[index])}"; } } break; case 2: _text = "${intToStr(index + 1)}${_checkStr(daySuffix)}"; break; case 3: case 5: _text = "${intToStr(index)}"; break; case 4: if (minuteInterval == null || minuteInterval < 2) _text = "${intToStr(index)}"; else _text = "${intToStr(index * minuteInterval)}"; break; case 6: // List _ampm = strAMPM ?? PickerLocalizations // .of(context) // .ampm; List _ampm = strAMPM; if (_ampm == null) _ampm = const ['AM', 'PM']; _text = "${_ampm[index]}"; break; case 7: _text = "${intToStr(index + 1)}"; break; case 8: _text = "${_checkStr(quarterSuffix)}${index + 1}"; break; case 9: _text = "${index + 1}${_checkStr(weekSuffix)}"; break; } return makeText(null, _text, picker.selecteds[_col] == index); } @override String getText() { return value.toString(); } @override int getColumnFlex(int column) { if (picker.columnFlex != null && column < picker.columnFlex.length) return picker.columnFlex[column]; if (getColumnType(column) == 0) return 3; return 2; } @override void doShow() { if (_yearBegin == 0) getLength(); var _maxLevel = getMaxLevel(); for (int i = 0; i < _maxLevel; i++) { int colType = getColumnType(i); switch (colType) { case 0: picker.selecteds[i] = value.year - _yearBegin; break; case 1: picker.selecteds[i] = value.month - 1; break; case 2: picker.selecteds[i] = value.day - 1; break; case 3: picker.selecteds[i] = value.hour; break; case 4: picker.selecteds[i] = minuteInterval == null || minuteInterval < 2 ? value.minute : value.minute ~/ minuteInterval; break; case 5: picker.selecteds[i] = value.second; break; case 6: picker.selecteds[i] = (value.hour > 12 || value.hour == 0) ? 1 : 0; break; case 7: picker.selecteds[i] = value.hour == 0 ? 11 : (value.hour > 12) ? value.hour - 12 - 1 : value.hour - 1; break; case 8: int quarter = getQuarter(); picker.selecteds[i] = quarter - 1; break; case 9: int week = getWeek(); picker.selecteds[i] = week - 1; break; } } } ///国际规定是周四为一周的第一天 static const int EPOCH_WEEK_DAY = DateTime.thursday; static const int EPOCH_JULIAN_DAY = 0; int getWeek() { ///当前选中时间 周几 var currentWeekDay = value.weekday; ///周四 int EPOCH_WEEK_DAY = DateTime.thursday; DateTime epoch = DateTime.utc(value.year); int offset = EPOCH_WEEK_DAY - currentWeekDay; int delta = EPOCH_JULIAN_DAY - offset; int week = (value.difference(epoch).inDays - delta) ~/ 7 + 1; return week; } ///获取季度 int getQuarter() { if (value.month >= 1 && value.month <= 3) { return 1; } else if (value.month >= 4 && value.month <= 6) { return 2; } else if (value.month >= 7 && value.month <= 9) { return 3; } else if (value.month >= 10 && value.month <= 12) { return 4; } else { return 0; } } @override void doSelect(int column, int index) { int year, month, day, h, m, s, q, w; year = value.year; month = value.month; day = value.day; h = value.hour; m = value.minute; s = value.second; q = getQuarter(); w = getWeek(); if (type != 2 && type != 6) s = 0; int colType = getColumnType(column); switch (colType) { case 0: year = _yearBegin + index; break; case 1: month = index + 1; break; case 2: day = index + 1; break; case 3: h = index; break; case 4: m = (minuteInterval == null || minuteInterval < 2) ? index : index * minuteInterval; break; case 5: s = index; break; case 6: if (picker.selecteds[_colAP] == 0) { if (h == 0) h = 12; if (h > 12) h = h - 12; } else { if (h < 12) h = h + 12; if (h == 12) h = 0; } break; case 7: h = index + 1; if (_colAP >= 0 && picker.selecteds[_colAP] == 1) h = h + 12; if (h > 23) h = 0; break; case 8: q = index + 1; if (q == 1) { month = 1; } else if (q == 2) { month = 4; } else if (q == 3) { month = 7; } else if (q == 4) { month = 10; } break; case 9: w = index + 1; break; } int __day = _calcDateCount(year, month); if (day > __day) day = __day; value = DateTime(year, month, day, h, m, s); if (minValue != null && (value.millisecondsSinceEpoch < minValue.millisecondsSinceEpoch)) { value = minValue; notifyDataChanged(); } else if (maxValue != null && value.millisecondsSinceEpoch > maxValue.millisecondsSinceEpoch) { value = maxValue; notifyDataChanged(); } ///年月周日类型,年或月或日改变的时候改动日期所在周也随之改变 if (type == 15) { int selectWeek = getWeek(); w = selectWeek - 1; notifyDataChanged(); } } int _getAPColIndex() { List<int> items = customColumnType ?? columnType[type]; for (int i = 0; i < items.length; i++) { if (items[i] == 6) return i; } return -1; } int _calcDateCount(int year, int month) { switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 2: { if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { return 29; } return 28; } } return 30; } String intToStr(int v) { return (v < 10) ? "0$v" : "$v"; } String _checkStr(String v) { return v == null ? "" : v; } } class _StateView extends StatefulWidget { final WidgetBuilder builder; const _StateView({Key key, this.builder}) : super(key: key); @override State<StatefulWidget> createState() => _StateViewState(); } class _StateViewState extends State<_StateView> { @override Widget build(BuildContext context) { return widget.builder(context); } update() { setState(() {}); } }
使用方法:
DateTime showPickerDate = DateTime.now(); int type; switch (timeFormat) {
case 'yyyyMMdd': showPickerDate = DateTime.parse(dateParam); type = PickerDateTimeType.kYMD; break; case 'yyyyMM': type = PickerDateTimeType.kYM; showPickerDate = DateTime.parse(dateParam + '01'); break; case 'yyyy': type = PickerDateTimeType.kY; showPickerDate = DateTime.parse(dateParam + '0101'); break; case 'yyyyQM': type = PickerDateTimeType.kYQ; //季度转时间月份DateTime List quDateList = dateParam.split('Q'); showPickerDate = DateTime.parse( quDateList[0] + getMonthWithQuarter(quDateList[1]) + '01'); break; case 'yyyyWEEK': type = PickerDateTimeType.kYMWD; showPickerDate = DateTime.now(); break; } new Picker( height: 250, adapter: new DateTimePickerAdapter( type: type, isNumberMonth: true, yearSuffix: "年", monthSuffix: "月", daySuffix: "日", quarterSuffix: "Q", weekSuffix: '周', value: showPickerDate, ), title: new Text(S.of(context).datePicker_Title), onConfirm: (Picker picker, List value) { print(picker.adapter.text); }, onSelect: (Picker picker, int index, List<int> selecteds) { this.setState(() { stateText = picker.adapter.toString(); print(stateText); }); }).show(Scaffold.of(context));
//根据季度获取时间月份
String getMonthWithQuarter(String quarterString) {
if (quarterString == '1') {
return '01';
} else if (quarterString == '2') {
return '04';
} else if (quarterString == '3') {
return '07';
} else if (quarterString == '4') {
return '10';
} else {
return "";
}
}