你真的會用Flutter日期類組件嗎

Flutter系統提供了一些日期選擇類組件,好比DayPicker、MonthPicker、YearPicker、showDatePicker、CupertinoDatePicker等,其中前4個爲Material風格組件,最後一個爲iOS風格組件。本文介紹了控件的基本用法及如何實現國際化,若是系統提供的國際化不知足你的須要,最後也介紹瞭如何實現自定義國際化。html

DayPicker

顯示給定月份的日期,並容許選擇一天。這些天以矩形網格排列,一週的每一天都有一列。ios

DayPicker有幾個必填參數,分別以下:git

  • 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),
)複製代碼

效果以下:async

selectableDayPredicate參數定義用戶的可選日期,返回false表示不可選,例如只可選今天之前的日期:ide

DayPicker(
  selectableDayPredicate: (date) {
    return date.difference(DateTime.now()).inMilliseconds < 0;
  },
  ...
)複製代碼

效果以下:post

今天之後的日期所有爲灰色,不可選狀態。ui

MonthPicker

可選擇的月份選擇器,在頂部有一個滾動的月份列表,每月份下面展現當前月份的天,本質上MonthPicker是滾動的月份列表+ DayPicker,用法以下:this

DateTime _selectedDate = DateTime.now();
MonthPicker(
  selectedDate: _selectedDate,
  onChanged: (date) {
    setState(() {
      _selectedDate = date;
    });
  },
  firstDate: DateTime(2020, 1),
  lastDate: DateTime(2020, 12),
)複製代碼

效果以下:spa

屬性和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',爲了和系統的區分,在根控件MaterialApplocalizationsDelegates屬性中增長:ZhCupertinoLocalizations.delegate,這個就是上面定義的國際化文件,效果以下:

注意:ZhCupertinoLocalizations.delegate要放在GlobalCupertinoLocalizations.delegate,的前面,系統加載順序爲從上到下。

效果以下:

交流

老孟Flutter博客地址(近200個控件用法):laomengit.com

歡迎加入Flutter交流羣(微信:laomengit)、關注公衆號【老孟Flutter】:

相關文章
相關標籤/搜索