2020年7月27日星期一

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

从一开始接触Flutter,相信读者都会铭记一句话,那就是——一切皆组件。今天我们就来体会一下这句话的神奇魔力,我们先从实际的产品需求说起。
我们先来看一个简化的运行图:

我们要实现如上图所示的日期选择器,App是iOS风格。
Flutter SDK自身有类似上图的日期选择器,但是Material Design的,于是我到Flutter库中找到了一个名为flutter_date_pickers的三方库,版本为0.1.4(https://pub.flutter-io.cn/packages/flutter_date_pickers)。
接下来就是集成这个库了,具体代码按照文档直接复制:

@overrideWidget 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崩溃了。报错堆栈信息如下:

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文件中出现问题,下面的代码是问题所在:

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);

在接下来的使用时,替换为:

localizations.datePickerDateOrder.index

即可。
但是,这毕竟需要改第三方库的源代码,有没有办法不改源码呢?答案是肯定的。
我们一开始就提到一切皆组件的概念,那么,有没有可能App依然使用iOS风格,然后把MaterialApp嵌套到CupertinoPageScaffold中呢?换一种说法,我们可不可以把MaterialApp和与之相关的Scaffold当做普通的组件,被CupertinoPageScaffold所包含呢?来看下面的代码:

@overrideWidget 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,也是没有问题的。
好了,本次分享到此结束,希望上述内容能够帮到你。

一切皆组件的Flutter,安能辨我是雄雌新蛋自贸区跨境通网站imgur2018卖家经营日记5招有效提高亚马逊产品的转化率和成交率!亚马逊评价被删怎么办? 亚马逊新品留评的正确方式美国为方便中国出境旅行者 特推电子旅行支票_美国旅游春节出境旅游价格上调 旅客可错开高峰提前预定冬天太冷,我们相约去海岛吧!_毛里求斯岛旅游

没有评论:

发表评论