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】:
![]() |
![]() |