從一開始接觸Flutter,相信讀者都會銘記一句話,那就是——一切皆組件。今天咱們就來體會一下這句話的神奇魔力,咱們先從實際的產品需求提及。
咱們先來看一個簡化的運行圖:app
咱們要實現如上圖所示的日期選擇器,App是iOS風格。
Flutter SDK自身有相似上圖的日期選擇器,可是Material Design的,因而我到Flutter庫中找到了一個名爲flutter_date_pickers的三方庫,版本爲0.1.4(https://pub.flutter-io.cn/packages/flutter_date_pickers)。
接下來就是集成這個庫了,具體代碼按照文檔直接複製:ide
@override Widget build(BuildContext context) { DatePickerRangeStyles styles = DatePickerRangeStyles( selectedPeriodLastDecoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.only( topRight: Radius.circular(10.0), bottomRight: Radius.circular(10.0))), selectedPeriodStartDecoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.only( topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)), ), selectedPeriodMiddleDecoration: BoxDecoration(color: Colors.yellow, shape: BoxShape.rectangle), ); return CupertinoPageScaffold( child: WeekPicker( selectedDate: DateTime.now(), onChanged: (dateRange) {}, firstDate: DateTime.now().subtract(Duration(days: 10)), lastDate: DateTime.now().add(Duration(minutes: 10)), datePickerStyles: styles) ); }
原本覺得能夠正常運行的,結果整個App崩潰了。報錯堆棧信息以下:ui
The following NoSuchMethodError was thrown building WeekPicker(dirty, dependencies: [_LocalizationsScope-[GlobalKey#678bc]]):
The getter 'firstDayOfWeekIndex' was called on null.
Receiver: null
Tried calling: firstDayOfWeekIndex指針
接着,根據堆棧信息找到代碼出錯位置,發現是這個庫中week_picker.dart文件中出現問題,下面的代碼是問題所在:code
MaterialLocalizations localizations = MaterialLocalizations.of(context); ISelectablePicker<DatePeriod> weekSelectablePicker = WeekSelectable( selectedDate, datePickerStyles.firstDayOfeWeekIndex ?? localizations.firstDayOfWeekIndex, firstDate, lastDate, selectableDayPredicate: selectableDayPredicate );
很明顯,這裏使用了MaterialLocalizations對象localizations,而MaterialLocalizations.of(context);方法返回了null,因此在接下來的代碼中拋出了空指針異常。
解決的方法很簡單,只要修改源碼,若是經過MaterialLocalizations來初始化localizations獲得null,那麼就經過CupertinoLocalizations來初始化它就好了。具體代碼以下:對象
CupertinoLocalizations localizations = CupertinoLocalizations.of(context);
在接下來的使用時,替換爲:blog
localizations.datePickerDateOrder.index
便可。
可是,這畢竟須要改第三方庫的源代碼,有沒有辦法不改源碼呢?答案是確定的。
咱們一開始就提到一切皆組件的概念,那麼,有沒有可能App依然使用iOS風格,而後把MaterialApp嵌套到CupertinoPageScaffold中呢?換一種說法,咱們可不能夠把MaterialApp和與之相關的Scaffold當作普通的組件,被CupertinoPageScaffold所包含呢?來看下面的代碼:ci
@override Widget build(BuildContext context) { DatePickerRangeStyles styles = DatePickerRangeStyles( selectedPeriodLastDecoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.only( topRight: Radius.circular(10.0), bottomRight: Radius.circular(10.0))), selectedPeriodStartDecoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.only( topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)), ), selectedPeriodMiddleDecoration: BoxDecoration(color: Colors.yellow, shape: BoxShape.rectangle), ); return CupertinoPageScaffold( child: MaterialApp( home: Scaffold( appBar: CupertinoNavigationBar(middle: Text('Incredible Flutter')), body: WeekPicker( selectedDate: DateTime.now(), onChanged: (dateRange) {}, firstDate: DateTime.now().subtract(Duration(days: 10)), lastDate: DateTime.now().add(Duration(minutes: 10)), datePickerStyles: styles)))); }
仔細閱讀上述代碼,可見:咱們只是在return語句中增長了MaterialApp和Scaffold組件,從新運行程序,結果能夠正常運行了。
另外還要注意,Scaffold中的appBar,咱們常常給定的是AppBar對象,但爲了實現iOS的界面風格,咱們將其值改成CupertinoNavigationBar,也是沒有問題的。
好了,本次分享到此結束,但願上述內容可以幫到你。文檔