一、生命周期
该界面前提:
①、StatefulWidget
②、WidgetsBindingObserver
③、@override didChangeAppLifecycleState
1 | import 'dart:async'; |
1、什么时候渲染完成?
使用场景:
该界面前提:
①、StatefulWidget
②、WidgetsBindingObserver
③、@override didChangeAppLifecycleState
1 | import 'dart:async'; |
使用场景:
1 | 数据传输一般处理方式:自上而下的一层一层传递数据。 |
大家都知道回调方法在父子Widget之间传值是非常有用的,特别是用于子Widget向父Widget传值,接。
定义一个回调函数类型
1 | typedef clickCallback = void Function(String value); |
将回调函数透出子Widget
1 | final clickCallback onClick; |
1.自定义notification
1 | class TestNotification extends Notification { |
2.子节点发送通知
1 | new RaisedButton( |
3.父节点使用NotificationListener进行监听子节点发出的通知,并作出响应
1 | new NotificationListener( |
我们app版本号写在pubspec.yaml里version字段后面。例如version: 1.0.0+3 其中+前面为版本号,后面为构建号。
采用包一层Container,进行对应的color设置。
1 | return Container( |
1 | return Scaffold( |
1 | class EmptyView extends StatelessWidget { |
设背景图为如上EmptyView,则设置代码如下:
1 |
|
默认情况下,大多数组件都会使用尽可能小的空间。所以如果不设置视图的大小的话,其会自动计算大小,只显示对应的大小。所以当你的视图不够大,而你却又想让它充满父视图的话。那应该进行一些对应的设置。
Container和Image等。如下:1 | return Image( |
缺点:需要计算大小,不建议使用。
Container后来设置width、height。1 | return Container( |
如果你不想/不能通过设置width、height属性的方式设置,则你可以构建一层Container或者ConstrainedBox,然后设置constraints的属性。建议两者的选择,使用ConstrainedBox会使得语意更明白。
1 | return Container( |
默认情况下,大多数组件都会使用尽可能小的空间:
ConstrainedBox 让部件可以使用期望的剩余空间。
BoxConstraints.expand 将会让组件使用无限制(所有可用)的空间,除非另有指定。
1 | BoxConstraints.tightFor(width: 80.0,height: 80.0), |
更多
BoxFit.fill:图显示,显示可能拉伸,充满
1 | /* 滑动效果 |
MVC、MVP、BloC、Redux四种架构在Flutter上的尝试
对比[MVC、MVP、BloC、Redux]四种架构的好坏,
对比[MVC、MVP、BloC、Redux]四种架构的好坏,最终还是的回归到状态管理上来。
MVC、MVP的状态管理都是采用setState方式,而BloC和Redux都有自己的一套状态管理。当项目最初不是很复杂的时候,采用
setState方式更新数据是可以的。但是随着功能的增加,你的项目将会有几十个甚至上百个状态,setState出现的次数便会显著增加,每次setState都会重新调用build方法,这势必对于性能以及代码的可阅读性带来一定的影响。所以就放弃了MVC、MVP这两种架构。最初对OpenGit_Flutter进行架构重构的时候,用到的是
Redux,到涉及到多个页面复用时,例如项目中的项目页,每涉及到一个复用页面就需要在state内定义一些列的变量,这是个很痛苦的过程,所以后面就放弃了用Redux,但是Redux在保存全局状态有优势,例如主题、语言、用户资料等。后面又尝试了BloC,该架构在多页面复用时,就没存在Redux的问题。所以最后我采用的架构是
Bloc+Redux,用BloC控制局部状态,用Redux控制全局状态。
Flutter中,dart的单例模式设计
1 | // 创建一个单例的Manager类 |
1 | import 'package:shared_preferences/shared_preferences.dart'; |
| 序号 | 描述 | 方式 | 方案 | 缺点 |
|---|---|---|---|---|
| 1 | 传统方法 | 页面 | APage + AWebView + AWebControl | 重进重载 |
| 2 | 单例WebControl | 页面 | APage + AWebView + ShareWebControl | 暂未发现 |
| 3 | 单例WebView | 页面 | APage + ShareWebView | Flutter因无法插入视图直接不适用 |
| 4 | 全局WebView 用法1 | 弹窗 | ShareWebView | 页面返回 |
| 5 | 全局WebView 用法2 | 假页面 | AWebPlaceholderPage+ShareWebView | 页面返回 |
重新梳理各方案特性:
| 传统方法 页面 |
单例WebControl 页面 |
单例WebView 页面 |
全局WebView 弹窗 |
全局WebView 假页面 |
|
|---|---|---|---|---|---|
| 附着物 | 页面 | 页面 | 页面 | 视图 | 视图 |
| 语言适用性 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 进出可系统控制 | ✅ | ✅ | ✅ | ❌ | ✅ |
| 侧滑返回系统控制 | ✅ | ✅ | ❌Flutter因无法插入视图直接不适用 | ❌ | 🚗侧滑会先看到白屏 |
| 重进可免重加载 | ❌重进重载 | ✅ | ✅ | ✅ | ✅ |
下面我们按WebView的存在形式,对WebView的方案进行各自的详细说明。
✅进出
✅侧滑返回
❌重进入游戏加载重复
🚗:Flutter因无法对视图树进行视图插入直接不适用。
不同地方共用一个webView视图()
1 | APage.addSubView(shareWebView); |
区别:全局webView:所有地方都使用同一个地方的webview。
1 | // 类似 player 的 control() |
在Flutter上,以Overlay的方式进行全局WebView的显示时候,底部页面仍会进行相应渲染事项,即仍占用CPU、GPU。
原因:轮播图、gif动画的渲染在弹出弹窗后,并未停止。
🚄优化:显示游戏时候,轮播图停止、gif动画停止(类似隐藏游戏的时候,游戏定时器及渲染关闭)。
目的:通过新页面来作为路由页。
若先弹出新页面再显示全局webView视图,页面会有新页面的假白屏问题。所以,应该是先显示再弹出。
同理若先隐藏全局webView视图再关闭新页面,页面会有新页面的假白屏问题。所以,应该是先关闭再隐藏。
以从全局webView视图进入一个app页面。若进入新页面是先关闭全局webView视图,再进入新页面,则从新页面返回的时候,返回位置会错乱(如果为了不错乱,则你必须自己判断返回到哪)。所以应该直接进入新页面。
官网地址:https://github.com/YMFE/yapi
下载你之前保存的 yapi项目:CQApp-api和yapi项目的数据:CQApp-api-mongodb两个git工程到本地或云服务器ECS上,然后运行。

运行成功的结果:
要运行项目,最终是要进入项目,执行node vendors/server/app.js 指令启动服务器,然后在浏览器打开 http://127.0.0.1:3000 访问。

yapi项目,然后启动yapi项目到Project中1 | cd Project/ |
yapi项目即在终端执行的命令如下:

如图,提示mongodb load success...则yapi启动成功。跳过如下MongoNetworkError错误,查看yapi的访问方法。
如果出现如下的MongoNetworkError问题,则原因是你执行node vendors/server/app.js 前,未先成功启动mongodb。从而导致MongoNetworkError错误。解决方式,请查看本文最后的
1、MongoNetworkError的解决
利用上述部署成功后的账号和密码,登录yapi网页。
密码:ymfe.org # 已修改为姓名全拼
登录后的界面截图如下:

yapi项目的数据mongodb到Project中1 | cd Project/ |
举例:下载mongodb的问题

yapi项目的数据mongodb
这样启动mongodb后,再执行node vendors/server/app.js,就能让yapi正确启动了。
官网地址:https://github.com/YMFE/yapi
官网 https://github.com/ymfe/yapi
使用yapi-cli 工具,部署 YApi 平台。
命令如下:
1 | npm install -g yapi-cli --registry https://registry.npm.taobao.org # 需要 nodejs环境 |
虽然只有两个命令,但是两个命令的执行分别需要nodejs环境和MongoDB环境。
所以,使用这两个命令前,我们先按需依次完成以下步骤,搭建yapi所需的nodejs环境和MongoDB环境。
1 | node -v |
如果能够执行此命令,则代表你已安装nodejs的环境,请不用再重复安装。如果没有,请看下一步3、nodejs环境的安装。
因为安装yapi的 npm install -g yapi-cli --registry https://registry.npm.taobao.org 那条命令,需要用到npm环境。如果没安装,则会失败如下:

所以请先检测您电脑是否已经安装了nodejs(7.6+)了。
安装nodejs(7.6+)。另关于node的安装,请查看本网站中的node.md
执行部署yapi的 yapi server 命令时候,此时看到的执行结果如下:
如果你未提前安装mongodb,则会在部署yapi的时候发生如下错误。
所以要完成yapi的成功部署,其还需要 mongodb(2.6+)
1 | mongo -version |
如果能够执行此命令,则代表你已安装mongodb的环境,请不用再重复安装。如果没有,请看3、yapi所需环境MongoDB的安装。
如果您是云服务器ECS,请跳过方法一,直接使用方法二终端命令安装MongoDB。
其他参考见:Mac OSX 平台安装 MongoDB
1、点击进入下载地址https://www.mongodb.com/download-center/enterprise

将下载下来的tgz解压后,放到/usr/local文件夹中,并改名为mongodb。

在改名为mongodb后,通过在终端执行open ~,找到并打开该目录下的.bash_profile中配置如下环境变量
1 | export PATH=${PATH}:/usr/local/mongodb/bin |
配置完后,关闭文件,终端执行如下命令,使得钢材配置的环境变量能够生效。
1 | cd ~ |
不执行 上述source命令的话, mongo -version 无法生效。
安装成功后,执行mongo -version,如果不提示 command not found,代表安装成功了。
至此,mongo安装完成,接下去进行启动mongo。
Linux平台安装MongoDB官网安装文档 https://www.runoob.com/mongodb/mongodb-linux-install.html
进入地址:https://www.mongodb.com/try/download/community

1 | cd 到某个目录,执行以下命令,下载文件 |

1 | -bash: ./mongo: cannot execute binary file: Exec format error |
查看系统是几位的终端命令为getconf LONG_BIT
测试方法:
1 | 1、使用wget下载 |

1 | tar -zxvf mongodb-linux-x86_64-rhel80-4.4.1.tgz |

输入vim /etc/profile编辑环境变量文件
1 | set for mongo |

插入完成后,执行source /etc/profile,使环境变量生效,之后执行以下命令,就可以看到有效了。
1 | mongo -version |
命令认识:
1 | --dbpath 设置数据存放目录 |
步骤:为MongoDB创建数据及日志存放的目录,这里我们就把它们放在/usr/local/var目录下。
创建数据目录: /usr/local/var/mongodb
创建日志存放的目录:/usr/local/var/log/mongodb

数据(必需)及日志存放的目录创建完成后,输入如下命令:
1 | --dbpath 设置数据存放目录 |

步骤:为MongoDB创建数据及日志存放的目录,这里我们新建一个单独的文件夹,如CQApp-api-mongodb来单独存放yapi的数据及日志。
1 | 创建存放的目录 |
生成后,文件如下:
1 | cd Project/CQApp-api-mongodb/ |

1 | 对于处理后台启动的mogodb的关闭,使用以下命令来关闭 |
yapi server 命令1 | yapi server |
http://0.0.0.0:9090,此时看到的结果如下:
执行过程如下:

部署/创建成功,截图如下:

密码:ymfe.org
这个账号密码,待会需要用于登录yapi网页界面使用。
此时你所填写的部署路径下,就会有所创建生成的yapi工程。
附:执行后mongodb config1
由私有库开源出来的只库代码,不含库示例的工程:https://gitee.com/dvlpPublic/iOS
目前含有:
每个Demo,包含
| 类别 | 工程名 | 备注 |
|---|---|---|
| iOS | xxx-yyy-iOS | |
| React | xxx-yyy-React | |
| ReactNative | xxx-yyy-ReactNative | |
| Flutter | xxx-yyy-Flutter | |
| 原生与 Web的JS 桥接 | xxx-yyy-JSBridge | |
| 原生与 React Native 桥接 | xxx-yyy-ReactNativeBridge | TSDemoBridgeDemo |
| 原生与 Flutter 桥接 | xxx-yyy-FlutterBridge | |
附:跨平台学习
CQDemo
| 序号 | 库 | 备注 | 状态 |
|---|---|---|---|
| 1 | 001-UIKit-BaseUIKit | 对BaseUIKit集成可设置Theme主题的库 | |
| 2 | 001-UIKit-BaseVCKit | 基础的视图控制器 BaseViewController ①ViewController ②NavigationController ③TabBarController(依赖CYLTabBarController和CQBridgeSTOLottie:桥接Swift版本的lottie-ios到OC中使用) |
|
| 3 | 002-UIKit-PopupContainer | 弹窗的容器信息(为各种不同的弹窗添加顶部下拉线、顶部工具栏等 CJPopupContainer CQPopupContainerAnimation |
|
| 3 | 002-UIKit-Overlay | ActionSheet、Alert、Toast、HUD | |
| 4 | 003-UIKit-Effect | 下拉刷新、上拉加载、空白页等 | |
| 5 | 004-UIKit-Image | 图片库 | |
| 5 | 004-UIKit-TextInput | 输入框库 | |
| 5 | 004-UIKit-Popup | ||
| 6 | 005-UIKit-List | ||
| 7 | 005-UIKit-List-ImageAddDelete | 图片添加删除列表 | |
| 8 | 006-UIKit-DatePicker | 日期选择 | |
| 9 | 006-UIKit-ImagePicker | 图片选择器(从相机中拍摄/从相册中选择) | |
| 10 | |||
| 11 | 008-UIKit-Segmented | Segmented | |
| 12 | 009-UIKit-Guide | 引导页 | |
| 13 | 011-UIKit-Line | 各种线条 Line | |
| 14 | |||
| 15 | |||
| 16 |
| 序号 | 库 | 备注 | 状态 |
|---|---|---|---|
| 1 | |||
| 14 | |||
| 15 | CJCustomView | 所有自定义视图存放的项目 | |
| 16 | CJAnimationKit | 动画库 https://gitee.com/dvlproad/CJAnimationKit | |
| APN | 推送 https://github.com/dvlproad/APNS | ||
| CJMonitor | 监听/Log https://github.com/dvlproad/CJMonitor | ||
| Environment | 环境切换 https://github.com/dvlproad/Feature-Environment-iOS | ||
1、CQAppBaseViewController
2、CQAppBaseNavigationController
CQAppTabBarController
CQBridgeSTOLottie:桥接Swift版本的lottie-ios到OC中使用
> Refresh
>
> Empty
CJImagePickerKit
1、系统”相册”和”相机”视图控制器的二次封装
2、自定义的”相册”视图控制器
CQImagePickerKit
1、”相册”和”相机”的权限判断:ImagePickerPermissionManager noPermissionBlock
(因为不同APP文案不同),所以权限判断才放在CQ中
2、系统”相册”和”相机”视图控制器的最终在具体APP中的封装
Collect App CommonUI
| 序号 | 库 | 备注 | 状态 |
|---|---|---|---|
| 1 | 001-Feature-ThirdLogin | 第三方登录 | |
| 2 | 002-Feature-Share | 分享 | |
| 3 | |||
| 4 | 004-Feature-Report | 举报 | |
| 5 | Feature-ImageFilter-iOS | 拼图/滤镜 |
1、Wechat 微信登录
含弹出分享面板
CQShareUtil的CQShareKit库 和 分享面板视图库CQShareSheet
CJBaiduMapKit
Collect App CommonFeature
*
1、原生与 H5 桥接
App Common JS Collect
组件化/模块化开发
Collect各个app的Service
APP LocationBasedService Collect 基于位置的服务
Collect App Login Feature
CJDemoModuleMineCollect App Main
Collect App Module
项目架构设计、组件化开发中各层次设计
图片识别(身份证) 语音识别 等
IM 即时通信
中秋博饼记录用
记忆训练、记忆宫殿
记忆宫殿
网约车、叫车软件
乘客端组件化开发
公务车司机端
公务车乘客端