Flutter:开发随笔

开发随笔

带皇冠的头像优化:

https://blog.csdn.net/lqw200931116/article/details/123372095

  • clipBehavior:此属性决定如何显示超出Stack的子组件是否被剪切;值为Clip.hardEdge时,超出部分会被剪裁(隐藏),值为Clip.none 时则不会,超出部分会显示

图片

为什么 Button 里 不要再设置颜色。猜测是由于DefaultTextStyle

[flutter 解决:setState() called after dispose()]

防止页面关闭执行setState()方法

解决方法

1
2
3
4
5
void updateState(fn){
if (mounted) {
setState(fn);
}
}

Flutter:获取状态state的几种方式

baseui_kit中的 data_util.dart

1
2
3
4
5
6
7
8
9
10
11
import 'package:flutter/material.dart';
// import 'dart:ui';

///枚举类型转string
String enumToString(o) => o.toString().split('.').last;

///string转枚举类型
T enumFromString<T>(Iterable<T> values, String value) {
return values.firstWhere((type) => type.toString().split('.').last == value,
orElse: () => null);
}

字符串与日期相互转换

String–>DateTime

1
DateTime.parse(String);

DateTime –>formatString

1
2
3
4
5
6
import 'package:date_format/date_format.dart';

formatDate(DateTime(2020, 12, 23) ,['yyyy', '-', 'mm', '-', 'dd']);
formatDate(DateTime(2020, 12, 23, 20, 40, 10), [‘HH’, ':', ‘nn’, ':', ‘ss’])

这里使用了日期格式化库:date_format。

Flutter 日期格式化库 date_format

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
flutter sdk 版本升级到2.0或者更高的版本后就发现运行时会报错:
Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:

- package:loading_indicator_view
- package:flutter_swiper
- package:flutter_page_indicator
- package:transformer_page_view

For solutions, see https://dart.dev/go/unsound-null-safety


FAILURE: Build failed with an exception.

也就是说以上有些包不支持 safety模式。

解决方案:--no-sound-null-safety
run
flutter run --no-sound-null-safety
build
flutter build apk --no-sound-null-safety

Flutter Error: Cannot run with sound null safety, because the following dependencies don‘t support

Flutter2 的 Sound null safety 是个什么鬼?!

flutter_webview_plugin和webview_flutter

iOS中WKWebView加载网页失败或者无网络状态判断

flutter嵌入HTML5页面,Flutter加载Html并实现与JS 的双向调用

几种常见视频格式ContentType和FileType对照表

Content-Type的格式

Content-Type:type/subtype ;parameter

type:主类型,任意的字符串,如text,如果是号代表所有;
subtype:子类型,任意的字符串,如html,如果是
号代表所有,用“/”与主类型隔开;
parameter:可选参数,如charset,boundary等。
例如:

Content-Type: text/html;
Content-Type: application/json;charset:utf-8;
Content-Type: application/x-www-form-urlencoded;charset:utf-8;

Flutter Fix

共享数据

三方库

flutter SliverAppBar

埋点

曝光

Flutter 解决TextOverflow.ellipsis截断字符

布局

布局的性能优化

Dart语言中文社区官网

Dart学习笔记(31):Future和异常处理

自定义Flutter控件

利用ScrollView实现TableView效果(实现复用)

Git-Flow

Git Flow

分支类型

  • master
  • dev
  • feature
  • hotfix
  • preproduct

master

线上代码分支。

【创建】在创建 repo 的时候创建 master 分支。

【命名】master

【描述】所有 release 的 tag 都打在 master,并且 master 不能直接 commit,只能通过 merge 来完成代码提交。

【输入】合并自 preproduct hotfix

【输出】hotfix

【销毁】master 分支是恒定存在的

dev

稳定开发分支

【创建】在创建 master 分支时,立即创建 dev 分支

【命名】dev

【描述】新版本需求来的时候管理员会从 dev 中拉出一条版本分支。dev 分支里保存完整的版本迭代和测试环境下已经修复的 bug。

【输入】合并自 feature hotfix preproduct

【输出】版本 release 时并入 master

【销毁】dev 分支是恒定存在的

feature / version

功能分支、新版本分支

【创建】当有新版本计划时,从 dev 中拉取

【命名】dev_1.0.0

【描述】存放某个版本的集成代码,包括这个版本在内测环境下的 bug 修复代码

【输入】开发人员 commit

【输出】版本结束后并入 dev

【销毁】并入后销毁

preproduct

某版本预生产分支

【创建】当某个版本的测试环境通过后,从 feature 分支并入 dev 分支时,从 dev 分支拉取出的分支

【命名】pre_1.0.0

【描述】存放某个版本的预生产代码,修复预生产时候的 bug

【输入】从 dev 中拉取,开发人员 commit

【输出】版本结束后同时并入 masterdev(不是并入 dev 再从 dev 并入 master

【销毁】并入后销毁

hotfix

热补丁分支

【创建】从 master 拉取。

【命名】hotfix/新版本号

【描述】需要紧急上线一个补丁版本,且已有新版本的 feature 分支时,需要创建该分支。如果当前没有新版本的 feature 分支,则按正常开发逻辑走流程。

【输入】开发人员 commit

【输出】先并入 master;判断 preproduct 是否存在 ? 并入 preproduct : 并入 dev

【销毁】并入后销毁

提交格式

使用 SourceTree 完成 commit,message 可以换行。

大致格式如下:

1
2
3
【信息分类】简略描述
详细描述
【URL】bugly 地址,或者 JIRA 地址

信息分类

Bugfix

【修复】修复自己开发过程中自测出来的问题

【修复-jira-{id}】修复 jira 上的问题,附带 bug id

【修复-bugly-{id}】修复 bugly 上的问题,附带 bug id

Feature

【新增】增加新的功能

Optmize

【优化】优化某些代码

Resource

【资源】资源文件的修改,不涉及代码

Configuration

【配置】修改版本号,修改打包脚本,修改工程配置,不涉及代码

PS

增加文件会更改到工程文件,此部分更改属于 Feature 的内容。

举例

增加某个功能:

1
2
【新增】购物车一键清空功能
批量删除购物车内的商品。

修复了某个自测 bug

1
2
【修复】清空购物车的时跳出支付页面
清空购物车的时候并没有删除商品,而是全选并支付。

修复了某个内测 bug

1
2
3
【修复-jira-10019】清空购物车按钮点击无效果
selector 编辑错误,导致 controller 没有响应事件。
【URL】http://jira.luckincoffee.com/products/luckincoffee/id_xxxxxx.html

修复了某个线上 bug

1
2
3
【修复-bugly-1191】WebView 闪退
对 WebView 中的编辑框操作(复制、全选、粘贴)时会闪退。
【URL】http://bugly.qq.com/luckincoffee/id_xxxxxx.html

时序图

feature

feature

GitFlow.alfredsnippets 使用

电脑安装 Alfred 3

双击 GitFlow.alfredsnippets 文件,导入到 Alfred 中

GitFlow.alfredsnippets 文件在此 repo 的 /page/iOS-Git-Flow 文件夹下可以找到

光标选中 SourceTree 的 commit 信息编辑框

激活 Alfred 窗口( 默认快捷键是 Option + Space ),输入 snip git 即可出现 commit 模板。

选中想要提交的内容,按 cmd + 数字 即可。

系统控制

为了统一,各视图分别使用如下组件

一、键盘遮挡问题

方案一:设置resizeToAvoidBottomPadding 为false

1
2
3
4
5
6
7
return Scaffold(
resizeToAvoidBottomPadding: false, //输入框抵住键盘
appBar: AppBar(
elevation: 0.0,
title: Text("登陆"),
),
);

方案二:在界面的body上用SingleChildScrollView包裹一下

1
2
body: SingleChildScrollView(
child:...

Flutter空安全

参考文章:

一、进行空安全适配

当开启空安全之后,然后运行下项目你会看到很多的报错,然后定位到报错的文件,大体有三类文件需要修改:

  1. 自定义Widget
  2. 数据模型(Model)
  3. 单例

详细看上面的参考文章。

二、项目空安全升级

升级 Flutter 空安全通常需要以下几个步骤:

  1. 更新 Flutter SDK 版本:首先需要更新 Flutter SDK 版本到支持空安全的版本。可以通过运行以下命令来更新 Flutter SDK:

    1
    flutter upgrade
  2. 添加空安全特性:在 Flutter SDK 更新后,需要在项目中添加空安全特性。可以通过运行以下命令来添加空安全特性:

    1
    2
    3
    dart migrate

    // 运行上述命令后,会自动添加空安全相关的代码和特性,例如非空断言、空值检查等。但是,需要根据项目的实际情况进行手动调整和修复。
  3. 验证代码:在添加空安全特性后,需要对代码进行验证,以确保代码中不存在空指针异常和其他错误。可以通过运行以下命令来验证代码:

    Copy

    1
    2
    3
    dart analyze

    // 运行上述命令后,会检查代码中存在的空指针异常和其他错误,并给出相应的提示和建议。需要根据提示和建议进行修复。
  4. 更新依赖库:在升级 Flutter 空安全时,可能需要更新一些依赖库,以确保依赖库也支持空安全。可以通过运行以下命令来更新依赖库:

    1
    2
    3
    flutter pub upgrade --null-safety

    // 运行上述命令后,会自动更新依赖库,以确保依赖库也支持空安全。
  5. 发布应用程序:在完成以上步骤后,需要重新构建和发布应用程序。可以通过运行以下命令来构建和发布应用程序:

    1
    2
    flutter build apk
    flutter install

以上是升级 Flutter 空安全的主要步骤,需要根据项目的实际情况进行调整和修复。在升级过程中,需要注意备份代码和依赖库,并在升级前进行充分的测试,以确保升级后应用程序的正常运行。

1、保证自己非空安全工程/package没有错误(此时版本号低于空安全的2.12.0)。

2、检查是否所在flutter工程依赖库是否都升级到了空安全版本

1
2
3
cd 到pubspec.yaml所在路径

dart pub upgrade --null-safety

3、执行 dart migrate,一键升级空安全。(容易犯的错:要一键升级的package,提前升级了空安全的版本号到2.12.0以上。)

企业微信截图_6607f7fd-ac49-4b68-b676-f3f0f4eac934

4、移动文件归属,解决依赖关系,使其完全不报红。

数据类

为了统一,各数据类(包含宏)分别使用如下:

一、颜色

暂无

二、TextStyle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'package:flutter_effect/flutter_effect.dart';

return Column(
children: <Widget>[
Text(
'Bold',
style: BoldTextStyle(fontSize: 17, color: Colors.red), // bold
),
Text(
'Medium',
style: MediumTextStyle(fontSize: 17, color: Colors.red), // medium
),
],
);

组件的使用-Button

为了统一,各视图分别使用如下组件

一、按钮Button

不用再写一堆嵌套地狱代码。(支持高亮效果,目前app按钮点击效果不佳,后续可能需要加,提前避免)

按钮的分类:

编号 类名 样式举例 备注
1 纯背景的按钮:
ThemeBGButton
纯背景的按钮
2 有边框的按钮:
ThemeBorderButton
有边框的按钮
3 切状态的按钮:
ThemeStateButton
状态按钮之未选中状态未选中状态(selected=false)
状态按钮之已选中状态已选中状态(selected=true)

1、纯背景的按钮:ThemeBGButton

纯背景的按钮
1
2
3
4
5
6
7
8
9
10
11
12
13
import 'package:flutter_baseui_kit/flutter_baseui_kit.dart';

ThemeBGButton(
//width: 300, // 不设置会根据内容自适应
//height: 80, // 不设置会根据内容自适应
bgColorType: ThemeBGType.pink,
needHighlight: true, // 默认false,不需要高亮
title: '红底白字的按钮',
titleStyle: ButtonBoldTextStyle(fontSize: 18.0),
cornerRadius: 20,
//enable: true, // 不设置,默认true
onPressed: () {},
),

如果你还需要在文字前添加图片,

纯背景并带有图片的按钮

可以通过 imageWidget 添加

1
2
3
4
5
6
7
8
9
10
import 'package:flutter_baseui_kit/flutter_baseui_kit.dart';

ThemeBGButton(
...
title: '以主题色(红色)为背景的按钮',
titleStyle: ButtonBoldTextStyle(fontSize: 18.0),
imageWidget: ImageAsset('images/xx.jpg', width: 22, height: 22,),
//imageTitleGap: 5, // 默认5
...
)

2、有边框的按钮:ThemeBorderButton

有边框的按钮
1
2
3
4
5
6
7
8
9
10
11
12
import 'package:flutter_baseui_kit/flutter_baseui_kit.dart';

ThemeBorderButton(
//width: 300, // 不设置会根据内容自适应
//height: 80, // 不设置会根据内容自适应
borderColorType: ThemeBGType.pink,
title: '白底红字红框的按钮',
titleStyle: ButtonBoldTextStyle(fontSize: 18.0),
cornerRadius: 20,
//enable: true, // 不设置,默认ture
onPressed: () {},
)

3、状态切换按钮:ThemeStateButton

未选中状态(selected=false):状态按钮之未选中状态
已选中状态(selected=true):状态按钮之已选中状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'package:flutter_baseui_kit/flutter_baseui_kit.dart';

ThemeStateButton(
//width: 300, // 不设置会根据内容自适应
//height: 80, // 不设置会根据内容自适应
normalBGColorType: ThemeBGType.pink,
normalTitle: '修改',
selectedTitle: '提交',
titleStyle: ButtonBoldTextStyle(fontSize: 18.0),
cornerRadius: 20,
selected: false,
//enable: true, // 不设置,默认ture
onPressed: () {},
)

其他按钮样式:

image-20211217121410240 image-20211218024015942 image-20211218024157575 image-20211218024244344

组件的使用-Cache

初始化:init

1
2
3
import 'package:flutter_cache_kit/flutter_cache_kit.dart';

LocalStorage.init();

Flutter 类型数据保存和获取方法:save/get

1
2
3
4
5
6
7
import 'package:flutter_cache_kit/flutter_cache_kit.dart';

// 保存方法:支持bool\int\double\String\List<String>
LocalStorage.save('test_string', string);

// 获取方法:支持bool\int\double\String\List<String>
String string = LocalStorage.get('test_string');

自定义的类的保存和获取方法:saveCustomBean\getCustomBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import 'package:flutter_cache_kit/flutter_cache_kit.dart';

// 保存
TSCustomBean customBean = TSCustomBean(
proxyId: '1001',
proxyIp: '192.168.1.1',
name: '代理',
);
LocalStorage.saveCustomBean(
'test_custom',
customBean,
itemToJson: (TSCustomBean bItem) {
return bItem.toJson();
},
);

// 获取
TSCustomBean customBean = LocalStorage.getCustomBean(
'test_custom',
fromJson: (bMap) {
return TSCustomBean.fromJson(bMap);
},
);

自定义的数组类的保存和获取方法:saveCustomBeans\getCustomBeans

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import 'package:flutter_cache_kit/flutter_cache_kit.dart';

// 保存
LocalStorage.saveCustomBeans(
'test_customBeans',
customBeans,
itemToJson: (TSCustomBean bItem) {
return bItem.toJson();
},
);

// 获取
List<TSCustomBean> customBeans = LocalStorage.getCustomBeans(
'test_customBeans',
fromJson: (bMap) {
return TSCustomBean.fromJson(bMap);
},
);

组件的使用-Overlay

为了统一,各视图分别使用如下组件

一、ToastUtil

弹出toast:

1
2
3
import 'package:flutter_overlay_kit/flutter_overlay_kit.dart';

ToastUtil.showMessage('登录成功');

开发卡在产品h5的时候,请使用如下弹出提示:

1
2
3
4
5
6
7
8
9
10
11
import 'package:flutter_overlay_kit/flutter_overlay_kit.dart';

// 需要产品补充完善需求
ToastUtil.showNeedProduct(
message: '我的首页中的愿望即将实现',
);

// 需要H5补充url
ToastUtil.showNeedH5(
message: '登录页面中的用户协议',
);

二、AlertUtil

弹窗

1
2
3
4
5
6
7
8
9
10
11
import 'package:flutter_overlay_kit/flutter_overlay_kit.dart';

AlertUtil.showCancelOKAlert(
context: context,
title: "退出登录",
message: "您确定要退出登录吗?",
cancelHandle: null,
okHandle: () {
print('点击确认按钮');
},
);

组件设计规范

为了统一,各视图分别使用如下组件

一、样式设计规范

在第六章进阶Flutter控件的封装一文中,我们已经知道使用继承父类式封装这种方式,不管在封装时候,还是在使用时候,写的代码都是最简洁的。而且后期如果要直接使用系统样式,也只需要改回类名,其他结构和属性都不用动即可

所以,即使是你所定义的类只有一个入参,也一定要遵守使用继承父类式封装的设计规范。

以下以按钮中 textStyle 的传值为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import 'package:flutter_baseui_kit/flutter_baseui_kit.dart';

ThemeBGButton(
//width: 300, // 不设置会根据内容自适应
//height: 80, // 不设置会根据内容自适应
bgColorType: ThemeBGType.pink,
title: '红底白字的按钮',
//titleStyle: ButtonThemeUtil.PingFang_FontSize_Bold(18.0), // bad
titleStyle: ButtonBoldTextStyle(fontSize: 18.0), // good
cornerRadius: 20,
//enable: true, // 不设置,默认true
onPressed: () {},
),

good:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 'package:flutter/material.dart';

// medium 的文本样式
class ButtonMediumTextStyle extends TextStyle {
final double fontSize;
// final Color color;

ButtonMediumTextStyle({
@required this.fontSize,
// this.color,
}) : assert(fontSize != null),
// assert(color != null),
super(
fontFamily: 'PingFang SC',
fontSize: fontSize,
fontWeight: FontWeight.w500,
// color: color,
);
}