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


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

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

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

    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所包含呢?来看下面的代码:

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

  • 相关阅读:
    A*算法研究
    C++实现动态数组
    Sublime Text3括号配对与代码包围效果BracketHighlighter
    SublimeREPL配置Python3开发
    Ubuntu16.04下使用sublime text3搭建Python IDE
    Netbeans使用笔记
    vscode: Visual Studio Code 常用快捷键
    OKR 第一阶段
    浏览器是如何工作的
    javascriptdocument load 和document ready的区别
  • 原文地址:https://www.cnblogs.com/wenhanxiao/p/13384928.html
Copyright © 2020-2023  润新知