Flutter数据和状态管理

一、对比[MVC、MVP、BloC、Redux]四种架构

  • MVC、MVP、BloC、Redux四种架构在Flutter上的尝试

    对比[MVC、MVP、BloC、Redux]四种架构的好坏,

    对比[MVC、MVP、BloC、Redux]四种架构的好坏,最终还是的回归到状态管理上来。MVCMVP的状态管理都是采用setState方式,而BloCRedux都有自己的一套状态管理。

    当项目最初不是很复杂的时候,采用setState方式更新数据是可以的。但是随着功能的增加,你的项目将会有几十个甚至上百个状态,setState出现的次数便会显著增加,每次setState都会重新调用build方法,这势必对于性能以及代码的可阅读性带来一定的影响。所以就放弃了MVCMVP这两种架构。

    最初对OpenGit_Flutter进行架构重构的时候,用到的是Redux,到涉及到多个页面复用时,例如项目中的项目页,每涉及到一个复用页面就需要在state内定义一些列的变量,这是个很痛苦的过程,所以后面就放弃了用Redux,但是Redux在保存全局状态有优势,例如主题、语言、用户资料等。后面又尝试了BloC,该架构在多页面复用时,就没存在Redux的问题。

    所以最后我采用的架构是Bloc+Redux,用BloC控制局部状态,用Redux控制全局状态。

  • Flutter Bloc状态管理 简单上手

  • [- Flutter-技能篇 -] 使用Provider前你应了解Consumer

  • Flutter状态管理provider的使用和封装

  • Flutter | 状态管理指南篇——Provider(鉴定为精450赞)

单例

Flutter中,dart的单例模式设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建一个单例的Manager类
class Manager {
// 工厂模式
factory Manager() =>_getInstance();
static Manager get instance => _getInstance();
static Manager _instance;
Manager._internal() {
// 初始化
}
static Manager _getInstance() {
if (_instance == null) {
_instance = new Manager._internal();
}
return _instance;
}
}

// 调用
// 无论如何初始化,取到的都是同一个对象
Manager manager = new Manager();
Manager manager2 = Manager.instance;

数据管理

shared_preferences 0.5.8

Flutter sharedPreferences使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import 'package:shared_preferences/shared_preferences.dart';

/// desc:本地储存
class SharedPreferenceUtil {
static const String UserTokenKey = "userTokenKey";

// 异步保存
Future setUserToken(String userToken) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(UserTokenKey, userToken);
}

// 异步删除
Future delUserToken() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(UserTokenKey);
}

// 异步读取
Future<String> getUserToken() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
String userToken = prefs.getString(UserTokenKey);
print('------userToken = $userToken-----');
return userToken;
}
}



// 使用
// 保存:
SharedPreferenceUtil.setUserToken("usertoken_zhangsan");

// 读取:
Future<String> userTokenFuture = SharedPreferenceUtil.getUserToken();
userTokenFuture.then((String userToken) {
print('------userToken = $userToken-----');
});

Flutter生命周期与路由

一、生命周期

该界面前提:

①、StatefulWidget

②、WidgetsBindingObserver

③、@override didChangeAppLifecycleState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:background_fetch/background_fetch.dart';

void main() {

// Enable integration testing with the Flutter Driver extension.
// See https://flutter.io/testing/ for more info.
runApp(new MyApp());

}

class MyApp extends StatefulWidget {

@override
_MyAppState createState() => new _MyAppState();

}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver{

@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);

print("--" + state.toString());
switch (state) {
case AppLifecycleState.inactive: // 处于这种状态的应用程序应该假设它们可能在任何时候暂停。
break;
case AppLifecycleState.resumed: // 应用程序可见,前台
break;
case AppLifecycleState.paused: // 应用程序不可见,后台
break;
case AppLifecycleState.detached: // detached
break;
}
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('前后台测试')
),

body: Container(
color: Colors.black,
child: Text('前后台测试'),
),

),

);

}

}

1、什么时候渲染完成?

使用场景:

二、路由

Flutter控件与布局相关

待做

Flutter获取版本号

我们app版本号写在pubspec.yamlversion字段后面。例如version: 1.0.0+3 其中+前面为版本号,后面为构建号。

一、基本设置

1、设置背景颜色/背景图

1.1、设置普通视图的背景色

采用包一层Container,进行对应的color设置。

1
2
3
4
return Container(
color: Colors.red, // 设置视图颜色
child: xxx,
);

1.2、设置页面的背景色

1
2
3
4
5
return Scaffold(
backgroundColor: Colors.yellow, // 设置页面背景颜色
appBar: _appBar(),
body: _pageWidget(),
);

2、设置背景图片

2.1、设置普通视图的背景图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class EmptyView extends StatelessWidget {
const EmptyView({Key key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration( // 设置视图的背景图/秀视图
image: new DecorationImage(
fit: BoxFit.cover, // 充满容器,可能会被截断。
image: new NetworkImage(
'https://randomuser.me/api/portraits/men/43.jpg'),
),
),
child: Container(
color: Colors.red.withOpacity(.5),
child: Center(
child: Text(
"我在图片的上面哦~",
style: TextStyle(color: Colors.white, fontSize: 33),
),
),
),
);
}
}

2.2、设置页面的背景图

设背景图为如上EmptyView,则设置代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow,
appBar: _appBar(),
body: _emptyView(),
);
}

// 特殊场景:如果你的页面上有TextField等会弹出键盘的视图。因为默认情况下键盘出现时是否应调整主体Scaffold的大小。所以,为了图片能正确显示,我们使用resizeToAvoidBottomInset指定在键盘出现时是否应调整主体的大小。
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow,
resizeToAvoidBottomInset: false, // 增加此行,指定在键盘出现时不调整主体的大小
appBar: _appBar(),
body: _emptyView(),
);
}

二、布局

1、充满

默认情况下,大多数组件都会使用尽可能小的空间。所以如果不设置视图的大小的话,其会自动计算大小,只显示对应的大小。所以当你的视图不够大,而你却又想让它充满父视图的话。那应该进行一些对应的设置。

1.1、设置width、height等于父视图大小方式(不建议)

①、如果视图有width和height属性,则直接设置。如ContainerImage等。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
return Image(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
image: AssetImage(
'lib/commonui/cq-guide-overlay/Resources/bg_背景遮罩.png'),
fit: BoxFit.fill,
),

return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.red,
child: xxx,
);

缺点:需要计算大小,不建议使用。

②、如果该视图没有width和height属性,则我们通过为该视图包一层Container后来设置width、height。
1
2
3
4
5
6
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.red,
child: xxx,
);

1.2、设置constraints方式

如果你不想/不能通过设置width、height属性的方式设置,则你可以构建一层Container或者ConstrainedBox,然后设置constraints的属性。建议两者的选择,使用ConstrainedBox会使得语意更明白。

1
2
3
4
5
6
7
8
9
10
11
12
13
return Container(
constraints: BoxConstraints(
minWidth: double.infinity,
minHeight: double.infinity,
),
color: Colors.red,
child: xxx,
);

return ConstrainedBox(
constraints: new BoxConstraints.expand(),
child: xxx,
),

默认情况下,大多数组件都会使用尽可能小的空间:

ConstrainedBox 让部件可以使用期望的剩余空间。

BoxConstraints.expand 将会让组件使用无限制(所有可用)的空间,除非另有指定。

1
2
3
BoxConstraints.tightFor(width: 80.0,height: 80.0),
// 等价于
BoxConstraints(minHeight: 80.0,maxHeight: 80.0,minWidth: 80.0,maxWidth: 80.0)

更多

2、图片的显示方式

BoxFit.fill:图显示,显示可能拉伸,充满

3、绝对布局

三、控件

Flutter 自定义组件之列表头悬浮

Flutter笔记-深入分析滑动控件

1
2
3
4
5
6
7
/* 滑动效果
* AlwaysScrollableScrollPhysics() 总是可以滑动,默认值
* NeverScrollableScrollPhysics禁止滚动
* BouncingScrollPhysics 内容超过一屏 上拉有回弹效果
* ClampingScrollPhysics 包裹内容 不会有回弹
*/
final ScrollPhysics physics;

三方控件

Flutter 中使用 video_player 播放视频

Flutter 中使用 video_player 播放视频

一个不用重加载的WebView

一、背景

  • 一个基于WebView的Cocos2d游戏,因为启动加载引擎会有3-5秒的加载时长。为了更好的游戏体验,希望启动后重新进入不用重新加载。

二、webView的方案汇总

序号 描述 方式 方案 缺点
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的方案进行各自的详细说明。

三、WebView方案之是单页面

1、传统:APage + AWebView + AControl

✅进出

✅侧滑返回

❌重进入游戏加载重复

2、webView视图”单例”—Flutter无效

🚗:Flutter因无法对视图树进行视图插入直接不适用。

不同地方共用一个webView视图()

1
2
3
APage.addSubView(shareWebView);
BPage.addSubView(shareWebView);
CPage.addSubView(shareWebView);

区别:全局webView:所有地方都使用同一个地方的webview。

3、webViewControl 单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 类似 player 的 control()
webView1.control = shareControl;
APage.addSubView(webView1);

webView2.control = shareControl;
BPage.addSubView(webView2);

webView3.control = shareControl;
CPage.addSubView(webView3)


build() {
//return shareWebView(); // ❌
return webViewWidget(control: shareControl)
}

四、WebView方案之是全局

1、直接弹窗

在Flutter上,以Overlay的方式进行全局WebView的显示时候,底部页面仍会进行相应渲染事项,即仍占用CPU、GPU。

原因:轮播图、gif动画的渲染在弹出弹窗后,并未停止。

🚄优化:显示游戏时候,轮播图停止、gif动画停止(类似隐藏游戏的时候,游戏定时器及渲染关闭)。

2、新页面+弹窗

目的:通过新页面来作为路由页。

2.1、显示方式:先显示全局webView视图,再弹出新页面

若先弹出新页面再显示全局webView视图,页面会有新页面的假白屏问题。所以,应该是先显示再弹出。

2.2、隐藏之返回方式:先关闭新页面,再隐藏全局webView视图

同理若先隐藏全局webView视图再关闭新页面,页面会有新页面的假白屏问题。所以,应该是先关闭再隐藏。

2.3、隐藏之进入新页面:直接进入新页面。

以从全局webView视图进入一个app页面。若进入新页面是先关闭全局webView视图,再进入新页面,则从新页面返回的时候,返回位置会错乱(如果为了不错乱,则你必须自己判断返回到哪)。所以应该直接进入新页面。

End

yapi的安装及其项目的创建和启动

官网地址:https://github.com/YMFE/yapi

前言/官网

官网 https://github.com/ymfe/yapi

一、安装yapi

使用yapi-cli 工具,部署 YApi 平台。

命令如下:

1
2
npm install -g yapi-cli --registry https://registry.npm.taobao.org	# 需要 nodejs环境
yapi server # 需要 MongoDB环境

虽然只有两个命令,但是两个命令的执行分别需要nodejs环境和MongoDB环境。

所以,使用这两个命令前,我们先按需依次完成以下步骤,搭建yapi所需的nodejs环境和MongoDB环境。

二、yapi所需环境nodejs的安装

1、nodejs环境的检测

1
node -v

如果能够执行此命令,则代表你已安装nodejs的环境,请不用再重复安装。如果没有,请看下一步3、nodejs环境的安装

2、未安装nodejs环境,导致的yapi安装失败

因为安装yapi的 npm install -g yapi-cli --registry https://registry.npm.taobao.org 那条命令,需要用到npm环境。如果没安装,则会失败如下:

image-20201117155309965

所以请先检测您电脑是否已经安装了nodejs(7.6+)了。

3、nodejs环境的安装

安装nodejs(7.6+)。另关于node的安装,请查看本网站中的node.md

三、yapi所需环境MongoDB的安装与启动

1、未配MongoDB环境,导致的yapi安装失败

执行部署yapi的 yapi server 命令时候,此时看到的执行结果如下:

yapi start1

如果你未提前安装mongodb,则会在部署yapi的时候发生如下错误。

yapi start error

所以要完成yapi的成功部署,其还需要 mongodb(2.6+)

2、MongoDB环境的检测

1
mongo -version

如果能够执行此命令,则代表你已安装mongodb的环境,请不用再重复安装。如果没有,请看3、yapi所需环境MongoDB的安装

3、yapi所需环境MongoDB的安装

方法一、可视化桌面安装

如果您是云服务器ECS,请跳过方法一,直接使用方法二终端命令安装MongoDB。

其他参考见:Mac OSX 平台安装 MongoDB

在Mac 安装MongoDB

1、点击进入下载地址https://www.mongodb.com/download-center/enterprise

mongodb download

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

mongodb install

在改名为mongodb后,通过在终端执行open ~,找到并打开该目录下的.bash_profile中配置如下环境变量

1
export PATH=${PATH}:/usr/local/mongodb/bin

配置完后,关闭文件,终端执行如下命令,使得钢材配置的环境变量能够生效。

1
2
3
4
5
6
cd ~
source ./.bash_profile


# 或者直接下面一句
source ~/.bash_profile

不执行 上述source命令的话, mongo -version 无法生效。

安装成功后,执行mongo -version,如果不提示 command not found,代表安装成功了。

mongodb install success

至此,mongo安装完成,接下去进行启动mongo。

方法二、终端命令安装MongoDB(云服务器常用的安装方式)

Linux平台安装MongoDB官网安装文档 https://www.runoob.com/mongodb/mongodb-linux-install.html

进入地址:https://www.mongodb.com/try/download/community

image-20201117221110499

1
2
3
cd 到某个目录,执行以下命令,下载文件
yum install libcurl openssl
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.1.tgz

image-20201117235817379

1、找到并提前测试所下载的mongodb能否在本操作系统下有效执行。如果无效,会出现以下错误
1
-bash: ./mongo: cannot execute binary file: Exec format error

查看系统是几位的终端命令为getconf LONG_BIT

测试方法:

1
2
3
4
5
6
# 1、使用wget下载

# 2、使用tar -zxvf解压缩后

# 3、直接进入解压缩后的mongodb的bin目录下,执行对应的命令

image-20210804131852567

2、有效后,再转移并设置环境变量
1
2
3
tar -zxvf mongodb-linux-x86_64-rhel80-4.4.1.tgz

mv mongodb-linux-x86_64-rhel80-4.4.1 /usr/local/mongodb

image-20201118004346856

输入vim /etc/profile编辑环境变量文件

1
2
# set for mongo
export PATH=/usr/local/mongodb/bin:$PATH

image-20210803224610402

插入完成后,执行source /etc/profile,使环境变量生效,之后执行以下命令,就可以看到有效了。

1
mongo -version

4、yapi所需环境MongoDB的启动

命令认识:

1
2
3
4
5
6
# --dbpath 设置数据存放目录
# --logpath 设置日志存放目录
# --fork 在后台运行

# mongod --dbpath <path to data directory> # 基础的运行命令
# mongod --dbpath <path to data directory> --logpath <path to log directory> --fork # 后台的运行命令(如果要--fork,则必须有--logpath参数)

方法一:可视化桌面操作(以MacOS为例)

1、为MongoDB创建数据(必需)及日志存放的目录(可选)

步骤:为MongoDB创建数据及日志存放的目录,这里我们就把它们放在/usr/local/var目录下。

创建数据目录: /usr/local/var/mongodb

创建日志存放的目录:/usr/local/var/log/mongodb

mongodb start1

2、执行命令启动 mongodb

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

1
2
3
4
5
6
7
8
# --dbpath 设置数据存放目录
# --logpath 设置日志存放目录
# --fork 在后台运行
mongod --dbpath /usr/local/var/mongodb --logpath /usr/local/var/log/mongodb/mongo.log --fork


cd /usr/local/var/
mongod --dbpath ./mongodb --logpath ./log/mongodb/mongo.log --fork

mongodb start2

方法二:终端命令操作(常用于云服务器)

1、为MongoDB创建数据(必需)及日志存放的目录(可选)

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

1
2
3
4
5
6
7
8
9
10
11
# 创建存放的目录
cd Project
mkdir CQApp-api-mongodb

# 创建数据目录data
sudo mkdir -p data
sudo chown -R 777 data

# 创建日志存放的目录log
sudo mkdir -p log
sudo chown -R 777 log

生成后,文件如下:

image-20210805014810744
2、执行命令启动 mongodb
1
2
cd Project/CQApp-api-mongodb/
mongod --dbpath ./data --logpath ./log/mongo.log --fork

image-20210805003329469

5、mongodb启动成功后,即可重新点击之前的开始部署/开始创建yapi项目。

6、yapi所需环境MongoDB的关闭

1
2
3
4
# 对于处理后台启动的mogodb的关闭,使用以下命令来关闭
pkill mongod

# 其他前台的,直接退出终端或者Ctrl+C结束就行了。

四、创建yapi项目

1、执行部署yapi的 yapi server 命令

1
yapi server

2、访问http://0.0.0.0:9090

此时看到的结果如下:

yapi start1

3、点击开始部署,

执行过程如下:

yapi start2

4、部署/创建成功

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

yapi start success

账号:admin@admin.com

密码:ymfe.org

这个账号密码,待会需要用于登录yapi网页界面使用。

此时你所填写的部署路径下,就会有所创建生成的yapi工程。

附:执行后mongodb config1

mongodb config1

五、yapi的项目运行

请查看 本博客中的yapi的项目运行.md

End

yapi的项目运行

官网地址:https://github.com/YMFE/yapi

一、下载已有的yapi的项目

下载你之前保存的 yapi项目:CQApp-apiyapi项目的数据:CQApp-api-mongodb两个git工程到本地云服务器ECS上,然后运行。

image-20211222150604187

二、运行效果预览

运行成功的结果:

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

yapi start4

三、终端运行yapi项目的步骤

1、(下载并)进入yapi项目,然后启动

1.1、下载已存在的yapi项目到Project中

1
2
cd Project/
git clone https://gitee.com/dvlpApi/CQApp-api

1.2、启动yapi项目

即在终端执行的命令如下:

image-20210805012844104

如图,提示mongodb load success...则yapi启动成功。跳过如下MongoNetworkError错误,查看yapi的访问方法。

如果出现如下的MongoNetworkError问题,则原因是你执行node vendors/server/app.js 前,未先成功启动mongodb。从而导致MongoNetworkError错误。解决方式,请查看本文最后的1、MongoNetworkError的解决
MongoNetworkError

2、yapi服务开启后,我们根据提示,再在浏览器访问地址,即可看到我们的效果。

yapi start5

3、登录yapi

利用上述部署成功后的账号和密码,登录yapi网页。

账号:admin@admin.com

密码:ymfe.org # 已修改为姓名全拼

登录后的界面截图如下:

image-20201024153331339

四、如启动yapi项目过程中遇到错误,各解决方式如下

1、MongoNetworkError的解决

1.1、下载已存在的yapi项目的数据mongodb到Project中

1
2
cd Project/
git clone https://gitee.com/dvlpApi/CQApp-api-mongodb

举例:下载mongodb的问题

image-20210805001123542

1.2、启动yapi项目的数据mongodb

image-20210805003329469

这样启动mongodb后,再执行node vendors/server/app.js,就能让yapi正确启动了。

End

第1节:UIKit+Feature

由私有库开源出来的只库代码,不含库示例的工程: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

附:跨平台学习

一、Demo

CQDemo

二、UIKit 组件

1、UIKit目录

序号 备注 状态
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

待归类的CJCustomView、CJAnimationKit、APN、CJMonitor、Environment

序号 备注 状态
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

2、基础UIKit各部分

001-UIKit-BaseUIKit——(对BaseUIKit集成可设置Theme主题的库)

001-UIKit-BaseVCKit-iOS——(基础的视图控制器 BaseViewController)

  • 001-UIKit-BaseVCKit-iOS

    1、CQAppBaseViewController

    2、CQAppBaseNavigationController

    • CQAppTabBarController.podspec

    CQAppTabBarController

    • CQBridgeSTOLottie.podspec

    CQBridgeSTOLottie:桥接Swift版本的lottie-ios到OC中使用

002-UIKit-PopupContainer——(弹窗的容器信息(为各种不同的弹窗添加顶部下拉线、顶部工具栏等))

002-UIKit-Overlay——(ActionSheet、Alert、Toast、HUD)

003-UIKit-Effect-iOS——(下拉刷新、上拉加载、空白页等)

> Refresh
>
> Empty

004-UIKit-Image——(图片库)

004-UIKit-TextInput/TextShow——(输入框库)

004-UIKit-Popup——(除Overlay外的其他弹窗)

005-UIKit-List——(列表)

005-UIKit-List-ImageAddDelete——(图片添加删除列表)

006-UIKit-DatePicker——(日期选择)

006-UIKit-ImagePicker——(图片选择)

  • 006-UIKit-ImagePicker-iOS

    CJImagePickerKit

    1、系统”相册”和”相机”视图控制器的二次封装

    2、自定义的”相册”视图控制器

    CQImagePickerKit

    1、”相册”和”相机”的权限判断:ImagePickerPermissionManager noPermissionBlock

    (因为不同APP文案不同),所以权限判断才放在CQ中

    2、系统”相册”和”相机”视图控制器的最终在具体APP中的封装

008-UIKit-Segmented——(Segmented)

009-UIKit-Guide——(引导页)

011-UIKit-Line——(各种线条 Line)

3、其他UIKit部分

CJCustomView——(所有自定义视图存放的项目)

CJAnimationKit——(动画库)

4、整合的UIKit工程

Collect App CommonUI

二、Feature 组件

1、Feature目录

序号 备注 状态
1 001-Feature-ThirdLogin 第三方登录
2 002-Feature-Share 分享
3
4 004-Feature-Report 举报
5 Feature-ImageFilter-iOS 拼图/滤镜

2、基础Feature各部分

001-Feature-ThirdLogin——(第三方登录)

1、Wechat 微信登录

002-Feature-Share-——(分享)

3、其他Feature部分

CJThirdPlatform——(依赖自第三平台上的封装)

CJBaiduMapKit

Feature-ImageFilter-iOS–拼图/滤镜

4、整合的Feature工程(暂无)

Collect App CommonFeature

*

六、TODO

1、原生与 H5 桥接

AppCommonJSCollect

App Common JS Collect

第3节:Module + App

八、Module模块

1、模块组件

CJModules

组件化/模块化开发

2、功能模块

AppServiceCollect

Collect各个app的Service

AppLBSCollect

APP LocationBasedService Collect 基于位置的服务

AppLoginCollect——(登录功能模块)

Collect App Login Feature

  • CJDemoModuleMine

AppMainCollect——(主页功能模块)

Collect App Main

3、整合的Module工程:AppModuleCollect

Collect App Module

九、App

1、Demo规范

CJDemoDemo

项目架构设计、组件化开发中各层次设计

2、Demo示例

CJDemoRecognition

图片识别(身份证) 语音识别 等

CJDemoIM

IM 即时通信

CJDemoMidAutumnFestival

中秋博饼记录用

CJDemoMemoryTraining

记忆训练、记忆宫殿

MemoryTrainingDemo

记忆宫殿

CJDemoCarHailing

网约车、叫车软件

web 工程示例

IntroduceCollect-app

3、历史App

BBXCarDriverClient

BBXCarPassengerClient

BBXPassengerClient_modularization

乘客端组件化开发

OfficialCarDriverClient

公务车司机端

OfficialCarPassengerClient

公务车乘客端

十、App整合