首先分清结构,主攻三大部分
一,基础控件
1,tabbar控件实现
Scaffold + Appbar + Tabbar + PageView
2,上下刷新列表
Flutter 中 为我们提供了 RefreshIndicator 作为内置下拉刷新控件;同时我们通过给 ListView 添加 ScrollController 做滑动监听,在最后增加一个 Item, 作为上滑加载更多的 Loading 显示。
这里需要注意一点是:可以利用 GlobalKey<RefreshIndicatorState> 对外提供 RefreshIndicator 的 RefreshIndicatorState,这样外部就 可以通过 GlobalKey 调用 globalKey.currentState.show();,主动显示刷新状态并触发 onRefresh 。
上拉加载更多在代码中是通过 _getListCount() 方法,在原本的数据基础上,增加实际需要渲染的 item 数量给 ListView 实现的,最后通过 ScrollController 监听到底部,触发 onLoadMore。
3,Loading框
默认系统提供了CircularProgressIndicator,但这里我要推荐一个第三方Loading库,flutte_spinkit ,通过简单的配置就可以使用丰富的Loading样式。
4,矢量图标库
矢量图标可以轻松定义颜色,任意调整大小不模糊,矢量图标库是引入ttf字体库文件实现,在flutter中通过icon控件,加载对应的icondata显示即可。这里推荐阿里巴巴的iconfont。
fonts: - asset: static/font/iconfont.ttf
5,路由跳转
Flutter中页面跳转是通过navigator实现的,路由跳转分为:带参跳转和不带参跳转。Navigator 的 push 返回的是一个 Future,这个Future 的作用是在页面返回时被调用的。也就是你可以通过 Navigator 的 pop 时返回参数,之后在 Future 中可以的监听中处理页面的返回结果。
二,数据模块
1,网络请求
dio ,http ,httpclient
2,Json序列化
在Flutter中,json序列化是特殊的。比如使用dio网络请求返回,如果配置了返回数据格式为json,实际上的收到的是一个map,而map使用不是很方便,所以需要再一次转化,转为实际的Model实体。
创建你的实体 Model 之后,继承 Object 、然后通过 @JsonSerializable() 标记类名。
通过 with _$TemplateSerializerMixin,将 fromJson 方法委托到 Template.g.dart 的实现中。 其中 *.g.dart、_$* SerializerMixin、_$*FromJson 这三个的引入, 和 Model 所在的 dart 的文件名与 Model 类名有关,具体可见代码注释和后面图片。
最后通过 flutter packages pub run build_runner build 编译自动生成转化对象。
3,Redux State -- flutter_redux
全局状态管理器 -- 跨控件管理,同步state,比如把用户信息存储在 redux 的 store 中, 好处在于: 比如某个页面修改了当前用户信息,所有绑定的该 State 的控件将由 Redux 自动同步修改。State 可以跨页面共享。
在redux中主要引入了action,reducer,store概念。
action 用于定义一个数据变化的请求。
reducer 用于根据 action 产生新状态
store 用于存储和管理 state,监听 action,将 action 自动分配给 reducer 并根据 reducer 的执行结果更新 state。
Action 用于定义一个数据变化的请求行为。Reducer 用于根据 Action 产生新状态,一般是一个方法。Store 用于存储和管理 state。所以一般流程为:1、Widget 绑定了 Store 中的 state 数据。2、Widget 通过 Action 发布一个动作。3、Reducer 根据 Action 更新 state。4、更新 Store 中 state 绑定的 Widget。
4,数据库
按照 sqflite 文档提供的方法,重新做了一小些修改,通过定义Provider操作数据库:
在 Provider 中定义表名与数据库字段常量,用于创建表与字段操作;
提供数据库与数据实体之间的映射,比如数据库对象与User对象之间的转化;
在调用 Provider 时才先判断表是否创建,然后再返回数据库对象进行用户查询。
三,其他功能
1,返回按键监听
Flutter 中 ,通过WillPopScope 嵌套,可以用于监听处理 Android 返回键的逻辑。其实 WillPopScope 并不是监听返回按键,如名字一般,是当前页面将要被pop时触发的回调。
2,前后台监听
WidgetsBindingObserver 包含了各种控件的生命周期通知,其中的 didChangeAppLifecycleState 就可以用于做前后台状态监听。
3,键盘焦点处理
一般触摸收起键盘也是常见需求,如下代码所示, GestureDetector + FocusScope 可以满足这一需求。
4,双端启动页
三,重点挖掘
1,Mixins
Mixin 能够更好的解决多继承中容易出现的问题,如:方法优先顺序混乱、参数冲突、类结构变得复杂化等等。
2,WidgetsFlutterBinding
WidgetsFlutterBinding 在 Flutter启动时runApp会被调用,作为App的入口,它肯定需要承担各类的初始化以及功能配置,这种情况下,Mixins 的作用就体现出来了。
3,inheriedWidget
InheritedWidget 是一个抽象类,在 Flutter 中扮演者十分重要的角色,或者你并未直接使用过它,但是你肯定使用过和它相关的封装。
InheritedWidget主要实现两个方法:
创建了InheritedElement,该Element属于特殊 Element, 主要增加了将自身也添加到映射关系表_inheritedWidgets【注1】,方便子孙 element 获取;同时通过notifyClients方法来更新依赖。
增加了updateShouldNotify方法,当方法返回 true 时,那么依赖该 Widget 的实例就会更新。
所以我们可以简单理解:InheritedWidget 通过InheritedElement实现了由下往上查找的支持(因为自身添加到_inheritedWidgets),同时具备更新其子孙的功能。
注1:每个 Element 都有一个_inheritedWidgets,它是一个 HashMap<Type, InheritedElement>,它保存了上层节点中出现的 InheritedWidget 与其对应 element 的映射关系。
接着我们看BuildContext,如上图,BuildContext其实只是接口,Element实现了它。InheritedElement是Element的子类,所以每一个 InheritedElement 实例是一个 BuildContext 实例。同时我们日常使用中传递的 BuildContext 也都是一个 Element 。
所以当我们遇到需要共享 State 时,如果逐层传递 state 去实现共享会显示过于麻烦,那么了解了上面的InheritedWidget之后呢?
是否将需要共享的 State,都放在一个 InheritedWidget 中,然后在使用的 widget 中直接取用就可以呢?答案是肯定的!所以如下方这类代码:通常如焦点、主题色、多语言、用户信息等都属于 App 内的全局共享数据,他们都会通过 BuildContext(InheritedElement) 获取。
综上所述,我们从先Theme入手。
如下方代码所示,通过给MaterialApp设置主题数据,通过Theme.of(context)就可以获取到主题数据并绑定使用。当MaterialApp的主题数据变化时,对应的 Widget 颜色也会发生变化,这是为什么呢(キ`゚Д゚´)!!?