一切皆組件的Flutter,安能辨我是雄雌

從一開始接觸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,也是沒有問題的。
好了,本次分享到此結束,但願上述內容可以幫到你。文檔

相關文章
相關標籤/搜索