你真的会用Flutter日期类组件吗

Flutter系统提供了一些日期选择类组件,比如DayPicker、MonthPicker、YearPicker、showDatePicker、CupertinoDatePicker等,其中前4个为Material风格组件,最后一个为iOS风格组件。本文介绍了控件的基本用法及如何实现国际化,如果系统提供的国际化不满足你的需要,最后也介绍了如何实现自定义国际化。
DayPicker
显示给定月份的日期,并允许选择一天。这些天以矩形网格排列,一周的每一天都有一列。
DayPicker有几个必填参数,分别如下:
- selectedDate:选中的日期,选中的日期有圆形背景。
- currentDate:当前日期,文字高亮。
- onChanged:用户选择的日期发生变化时回调。
- firstDate:可选日期的开始值。
- lastDate:可选日期的结束值。
- displayedMonth:显示的月份
显示2020年5月,代码如下:
DateTime _selectedDate = DateTime.now();
DayPicker(
  selectedDate: _selectedDate,
  currentDate: DateTime.now(),
  onChanged: (date) {
    setState(() {
      _selectedDate = date;
    });
  },
  firstDate: DateTime(2020, 5, 1),
  lastDate: DateTime(2020, 5, 31),
  displayedMonth: DateTime(2020, 5),
)
效果如下:

selectableDayPredicate参数定义用户的可选日期,返回false表示不可选,例如只可选今天以前的日期:
DayPicker(
  selectableDayPredicate: (date) {
    return date.difference(DateTime.now()).inMilliseconds < 0;
  },
  ...
)
效果如下:

今天以后的日期全部为灰色,不可选状态。
MonthPicker
可选择的月份选择器,在顶部有一个滚动的月份列表,每个月份下面展示当前月份的天,本质上MonthPicker是滚动的月份列表+ DayPicker,用法如下:
DateTime _selectedDate = DateTime.now();
MonthPicker(
  selectedDate: _selectedDate,
  onChanged: (date) {
    setState(() {
      _selectedDate = date;
    });
  },
  firstDate: DateTime(2020, 1),
  lastDate: DateTime(2020, 12),
)
效果如下:

属性和DayPicker基本一致。
YearPicker
年份选择器,用法如下:
YearPicker(
  selectedDate: _selectedDate,
  onChanged: (date) {
    setState(() {
      _selectedDate = date;
    });
  },
  firstDate: DateTime(2000, 1),
  lastDate: DateTime(2020, 12),
)
效果如下:

年份选择器和月份选择器略有不同,年份选择器并不包含当前年份下的月份。
不管是YearPicker,还是MonthPicker、DayPicker,"我们都很少直接使用",而是使用showDatePicker,它会创建一个日期选择器对话框。个人觉得showDatePicker的样式风格不是很符合国内的审美,我们可能更多的时候是使用YearPicker、MonthPicker和DayPicker自定义日期控件。
showDatePicker
showDatePicker并不是一个新的控件,而是封装了YearPicker和MonthPicker,并进行了联动,用法如下:
RaisedButton(
  onPressed: () async {
    var result = await showDatePicker(
        context: context,
        initialDate: DateTime.now(),
        firstDate: DateTime(2020),
        lastDate: DateTime(2030));
    print('$result');
  },
)
效果如下:

相关参数介绍如下:
- initialDate初始化时间,通常情况下设置为当前时间。
- firstDate表示开始时间,不能选择此时间前面的时间。
- lastDate表示结束时间,不能选择此时间之后的时间。
- showDatePicker方法是Future方法,点击日期选择控件的确定按钮后,返回选择的日期。
- selectableDayPredicate参数定义用户的可选日期,返回false表示不可选,与DayPicker用法相同。
builder参数可用于包装对话框窗口小部件以添加继承的窗口小部件,例如Theme,设置深色主题用法如下:
showDatePicker(
  builder: (context, child) {
    return Theme(
      data: ThemeData.dark(),
      child: child,
    );
  },
	...
)
效果如下:

上面是Material风格的日期控件,下面介绍下iOS风格的日期控件。
CupertinoDatePicker
ios风格的日期选择器,用法如下:
 var _dateTime = DateTime.now();
CupertinoDatePicker(
  initialDateTime: _dateTime,
  onDateTimeChanged: (date) {
    setState(() {
      _dateTime = date;
    });
  },
)
效果如下:

mode参数设置日期的格式:
- time:只显示时间,效果:4 | 14 | PM
- date:只显示日期,效果:July | 13 | 2012
- dateAndTime:时间和日期都显示,效果: Fri Jul 13 | 4 | 14 | PM
设置最大日期和最小日期:
CupertinoDatePicker(
  minimumDate: DateTime.now().add(Duration(days: -1)),
  maximumDate: DateTime.now().add(Duration(days: 1)),
  ...
)
效果如下:

使用24小时制:
CupertinoDatePicker(
  use24hFormat: true,
	...
)
showTimePicker
时间选择器只能通过showTimePicker的方式来调用,用法如下:
RaisedButton(
  onPressed: () async {
    showTimePicker(
        context: context, initialTime: TimeOfDay.now());
  },
)
效果如下:

builder参数用于控制子控件,可以向DatePicker一样设置深色主题,还可以设置其显示24小时,用法如下:
showTimePicker(
    context: context,
    initialTime: TimeOfDay.now(),
    builder: (context, child) {
      return MediaQuery(
        data: MediaQuery.of(context)
            .copyWith(alwaysUse24HourFormat: true),
        child: child,
      );
    });
效果如下:

CupertinoTimerPicker
CupertinoTimerPicker 是ios风格的时间选择器,基本用法如下:
CupertinoTimerPicker(
  onTimerDurationChanged: (Duration duration){
  },
)
效果如下:

设置只显示小时和分钟:
CupertinoTimerPicker(
  mode: CupertinoTimerPickerMode.hm,
  ...
)
默认情况下,CupertinoTimerPicker显示0:0:0,设置显示当前时间:
var now = DateTime.now();
return Container(
  height: 200,
  child: CupertinoTimerPicker(
    initialTimerDuration: Duration(hours: now.hour,minutes: now.minute,seconds: now.second),
    onTimerDurationChanged: (Duration duration) {},
  ),
);
国际化
增加国际化处理,在pubspec.yaml添加支持:
dependencies:
  flutter_localizations:
    sdk: flutter
在顶级控件MaterialApp添加支持,具体信息可查MaterialApp控件:
MaterialApp(
  localeListResolutionCallback:
          (List<Locale> locales, Iterable<Locale> supportedLocales) {
        return Locale('zh');
      },
      localeResolutionCallback:
          (Locale locale, Iterable<Locale> supportedLocales) {
        return Locale('zh');
      },
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('zh', 'CH'),
        const Locale('en', 'US'),
      ],
  ...
)
以上方式对所有日期控件都有效果,效果如下:


自定义国际化
我们对iOS风格的控件自定义国际化为例,新建新的类MyLocalizationsDelegate:
class MyLocalizationsDelegate
    extends LocalizationsDelegate<CupertinoLocalizations> {
  const MyLocalizationsDelegate();
  @override
  bool isSupported(Locale locale) => locale.languageCode == 'zh';
  @override
  Future<CupertinoLocalizations> load(Locale locale) =>
      ZhCupertinoLocalizations.load(locale);
  @override
  bool shouldReload(MyLocalizationsDelegate old) => false;
  @override
  String toString() => 'DefaultCupertinoLocalizations.delegate(zh)';
}
ZhCupertinoLocalizations定义如下:
class ZhCupertinoLocalizations implements CupertinoLocalizations {
  const ZhCupertinoLocalizations();
  static const List<String> _shortWeekdays = <String>[
    '自周一',
    '自周二',
    '自周三',
    '自周四',
    '自周五',
    '自周六',
    '自周日',
  ];
  static const List<String> _shortMonths = <String>[
    '1月',
    '2月',
    '3月',
    '4月',
    '5月',
    '6月',
    '7月',
    '8月',
    '9月',
    '10月',
    '11月',
    '12月',
  ];
  static const List<String> _months = <String>[
    '1月',
    '2月',
    '3月',
    '4月',
    '5月',
    '6月',
    '7月',
    '8月',
    '9月',
    '10月',
    '11月',
    '12月',
  ];
  @override
  String datePickerYear(int yearIndex) => yearIndex.toString();
  @override
  String datePickerMonth(int monthIndex) => _months[monthIndex - 1];
  @override
  String datePickerDayOfMonth(int dayIndex) => dayIndex.toString();
  @override
  String datePickerHour(int hour) => hour.toString();
  @override
  String datePickerHourSemanticsLabel(int hour) => hour.toString() + " o'clock";
  @override
  String datePickerMinute(int minute) => minute.toString().padLeft(2, '0');
  @override
  String datePickerMinuteSemanticsLabel(int minute) {
    if (minute == 1) return '1 分';
    return minute.toString() + ' 分';
  }
  @override
  String datePickerMediumDate(DateTime date) {
    return '${_shortWeekdays[date.weekday - DateTime.monday]} '
        '${_shortMonths[date.month - DateTime.january]} '
        '${date.day.toString().padRight(2)}';
  }
  @override
  DatePickerDateOrder get datePickerDateOrder => DatePickerDateOrder.mdy;
  @override
  DatePickerDateTimeOrder get datePickerDateTimeOrder =>
      DatePickerDateTimeOrder.date_time_dayPeriod;
  @override
  String get anteMeridiemAbbreviation => '上午';
  @override
  String get postMeridiemAbbreviation => '下午';
  @override
  String get todayLabel => '今天';
  @override
  String get alertDialogLabel => 'Alert';
  @override
  String timerPickerHour(int hour) => hour.toString();
  @override
  String timerPickerMinute(int minute) => minute.toString();
  @override
  String timerPickerSecond(int second) => second.toString();
  @override
  String timerPickerHourLabel(int hour) => hour == 1 ? '小时' : '小时';
  @override
  String timerPickerMinuteLabel(int minute) => '分.';
  @override
  String timerPickerSecondLabel(int second) => '秒.';
  @override
  String get cutButtonLabel => '剪贴';
  @override
  String get copyButtonLabel => '拷贝';
  @override
  String get pasteButtonLabel => '黏贴';
  @override
  String get selectAllButtonLabel => '选择全部';
  static Future<CupertinoLocalizations> load(Locale locale) {
    return SynchronousFuture<CupertinoLocalizations>(
        const ZhCupertinoLocalizations());
  }
  /// A [LocalizationsDelegate] that uses [DefaultCupertinoLocalizations.load]
  /// to create an instance of this class.
  static const LocalizationsDelegate<CupertinoLocalizations> delegate =
      MyLocalizationsDelegate();
}
注意开始的属性_shortWeekdays,这个属性表示星期几,故意写成'自周x',为了和系统的区分,在根控件MaterialApp的localizationsDelegates属性中增加:ZhCupertinoLocalizations.delegate,这个就是上面定义的国际化文件,效果如下:

注意:ZhCupertinoLocalizations.delegate要放在GlobalCupertinoLocalizations.delegate,的前面,系统加载顺序为从上到下。
效果如下:

交流
老孟Flutter博客地址(近200个控件用法):http://laomengit.com
欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:
|  |  | 
你真的会用Flutter日期类组件吗的更多相关文章
- Flutter 布局类组件:简介
		前言 布局类组件都会包含一个或多个子组件,不同的布局类组件对子组件排版(layout)方式不同. 我们知道,Element树才是最终的绘制树,Element树是通过Widget树来创建的(通过Widg ... 
- Flutter 裁剪类组件 最全总结
		注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 ClipRect ClipRect组件使用矩形裁剪子组件, ... 
- Flutter 布局类组件:层叠布局(Stack和Positioned)
		前言 层叠布局,即子组件可以根据距父容器四个角的位置来确定自身的位置.绝对定位运行子组件堆叠起来,即按照代码中声明的顺序. Flutter中使用Stack和Positioned这两个组件来配合实现绝对 ... 
- Flutter 布局类组件:流式布局(Wrap和Flow)
		前言 把超出屏幕显示范围会自动折行的布局称为流式布局.Flutter中通过Wrap和Flow来支持流式布局,将Row换成Wrap后溢出部分则会自动折行. Wrap 接口描述 Wrap({ Key ke ... 
- Flutter 布局类组件:弹性布局(Flex)
		前言 弹性布局允许子组件按照一定比例来分配父容器空间,Flutter中的弹性布局主要通过Flex和Expanded来配合实现. Flex Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方 ... 
- Flutter 布局类组件:线性布局(Row和Column)
		前言 所谓线性布局,即指沿水平或垂直方向排布子组件.Flutter中通过Row和Column来实现线性布局,并且它们都继承自弹性布局(Flex). 接口描述 Row({ Key key, // 表示子 ... 
- Flutter中的日期、格式化日期、日期选择器组件
		Flutter中的日期和时间戳 //獲取當前日期 DateTime _nowDate = DateTime.now(); print(_nowDate);//2019-10-29 10:57:20.3 ... 
- Java日期处理组件joda-time
		版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/175 Java日期处理组件joda-time 平常在开发过 ... 
- 日期类时间类,日期时间类,单例模式,装箱与拆箱,数字类随机数,BigDecimal总结
		1.日期类,时间类,日期时间类 初步日期使用方法及格式转换方法(旧方法): 格式://Mon Jul 30 11:26:05 CST 2018 年月日时分秒 CST代表北 ... 
随机推荐
- D3平移和缩放后的点击坐标(D3 click coordinates after pan and zoom)
			我使用D3库来创建绘图应用程序. 我需要在用户单击的坐标上绘制对象(为了简单起见).问题是当用户使用平移&缩放和移动视口.然后对象是错误的位置的地方(我想问题是事件坐标是相对于svg元素而不是 ... 
- G - Pairs Forming LCM LightOJ - 1236 (质因子分解)
			题解:这道题要从n的角度来考虑i和j. n可以表示为n=a1^p1*a2^p2*a3^p3.......n=lcm(i,j),那么质因子a1^p1,a1可以在i或者j中,并且p1=max(a1i,a1 ... 
- 基于netty实现rpc框架-spring boot服务端
			demo地址 https://gitee.com/syher/grave-netty RPC介绍 首先了解一下RPC:远程过程调用.简单点说就是本地应用可以调用远程服务器的接口.那么通过什么方式调用远 ... 
- 《并发编程的艺术》阅读笔记之Volatile
			来源 在 JDK1.2 之前,Java的内存模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的.而在当前的 Java 内存模型下,线程可以把变量保存本地内存(比如机器的寄存器)中,而不 ... 
- C# 序列化之二进制
			序列化:又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制.其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方. 一般有三种方式:1.是使用BinaryF ... 
- 科学计算包Numpy
			Numpy 用于科学计算的python模块,提供了Python中没有的数组对象,支持N维数组运算.处理大型矩阵.成熟的广播函数库.矢量运算.线性代数.傅里叶变换以及随机数生成等功能,并可与C++.FO ... 
- Java 基础之详解 Java IO
			Java IO基本概念 Java IO:即Java输入/输出系统,区分Java的输入和输出:把自己当成程序, 当你从外边读数据到自己这里就用输入(InputStream/Reader), 向外边写数据 ... 
- notepad正则删除关键词所在行
			转自:http://www.gangzi.net/article/615.htm 查找:^.*大师兄.*$替换为:(空) 如果不留空行:查找:^.*大师兄.*\r?\n替换为:(空)注意:Notepa ... 
- Linux 获取网卡名字列表
			lspci | egrep -i --color 'network|ethernet' 
- Hexo博客插入图片的方法
			Hexo博客插入图片的方法 hexo图片blog hexo blog 插入图片的方法总结 hexo 的blog 内容是根据 markdown 文件的内容生成的html文件, 生成的文件全部在 /pub ... 
