Flutter开发规范
中交兴路使用Flutter框架开发规范,大家都可以贡献自己的想法,可以通过沟通或提交分支的形式表达自己想法,讨论后达成共识就可以合并到主干,文档采用markdown语法来书写,每个版本会生成相关pdf文档
目录结构规范
![](https://img.haomeiwen.com/i1774399/5ec7e2c9ee820f79.png)
-
lib文件夹是flutter主要代码目录,通常不会直接在根目录下直接创建dart文件,而是会根据功能点、模块、属性等创建子文件夹,在相应子文件夹中创建相应dart文件,当然子文件下依然可以再创建文件夹,将目标文件所属角色细化;
-
文件夹通常是小写单词,小驼峰法使用较少,不推荐使用下划线连接法;
-
通常main(mian.dart程序入口)会直接创建在根目录下;
命名规范
- 文件和文件夹命名规范
单词全部小写,多个单词时中间采用英文下划线分割
![](https://img.haomeiwen.com/i1774399/c8b7eb6beb6f73c9.png)
- 常量和变量命名规范
常量和变量命名采用小驼峰命名法,第一个单词小写,其他单词首字母大写。 代码如下:
/// 常量命名
const String key = 'LDDRDS323DRFDD';
/// 变量命名
String personName = '张三';
int age = 10;
- 类的名称命名规范
类名采用大驼峰命名法。所有单词首字母也大写,不使用分隔符。
私有类命名加英文下划线前缀,其它部分遵循类名称命名规则,采用大驼峰命名法。
属性命名使用小驼峰命名法,第一个单词小写,其他单词首字母大写,不使用分割符
私有属性加英文下划线前缀,其它部分遵循属性命名规则
class Person{
final String name; /// 名字
final String closthColor; /// 衣服颜色
String _sex; /// 私有属性,以英文下划线开始
}
class _PrivateInfo{
final String bankPassword; /// 银行卡密码
final String safePassword; /// 保险柜密码
}
class BankCardTile{ /// 多个单词命名规则
final String title;
final int index;
}
- 方法命名规范
方法命名使用小驼峰命名法,第一个单词首字母小写,其他单词首字母大写,不使用分割符
class LoginPage{
Future<bool> login(String userName, String password){
/// code
}
void changeLoginStyle(LoginStyle style){ /// 改变登录方式
/// code
}
}
私有方法加英文下划线前缀
class LoginPage{
Future<bool> _sendMsgCode(String phoneName){
/// code
}
}
- 图片命名单词全部小写,多个单词时中间采用英文下划线分割,
注意:flutter不支持中文,中文名字的图片在andriod系统中无法识别
- 枚举类命名规则
枚举名采用大驼峰命名法。第一个单词首字母大写,其他单词首字母也大写,不使用分隔符。
枚举值采用小驼峰命名法,第一个单词首字母小写,其他单词首字母大写。
///枚举命名采取大驼峰命名, 枚举值得采用小驼峰命名
enum BankCardListType {
myCard, // 我的银行卡列表
cleanType, // 结算对象银行卡列表
}
代码规范
- if else使用大括号,尽可能不省略;
if (yet) {
/// code
}
- 注意使用@required、assert
Future sendRequestWithURL({
@required String urlString,
@required String requestId,
String jsonParams = "",
RequestType requestType = RequestType.post,
Map<String, dynamic> headers = const {},
Map<String, dynamic> params = const {},
bool isShowLog = false,
bool isFormData = false,
int timeout = 5000,
}) async {
assert(urlString != null);
assert(urlString != '');
assert(headers != null);
assert(params != null);
assert(requestId != null);
}
-
函数体代码不宜过多,最好在20 - 30行以内; 一个方法中尽量只做一件事。
-
控制嵌套层数,最好能控制在4层
@override
Widget build(BuildContext context) {
CustomThemeData currentTheme = context.watch<ThemesManager>().currentTheme;
return Scaffold(
appBar: UniversalWidgets.customAppBar(context,title:' 添加银行卡'),
body: SafeArea(
child: SingleChildScrollView(
child: Container(
color: currentTheme.pageBackgroundColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Divider(height: 10, color: currentTheme.pageBackgroundColor),
SizedBox(height: 320, child: _listView(context)),
Container(
margin: EdgeInsets.fromLTRB(0, 45.5, 0, 0),
child: _saveButtonWidget(),
)
],
)),
),
),
);
}
-
代码长度不要超过100个字符的宽度,也是Andriod studio折行宽度(下图红色框中的白线就是100个字符的位置)
折行线
-
类文件的代码总度长度尽量控制在1000行以内,超过1000行考虑拆分功能。
-
封装、继承、混入、接口在开发过程常要多运用;相关知识点参考
https://www.jianshu.com/p/62e02f239f74 -
在既要import导入,又需要export导出文件时,一定先全部import再export,不要交替进行。
library zjxl_digital_user_center;
import 'package:flutter/cupertino.dart';
import 'package:zjxl_digital_user_center/src/user_center_config.dart';
export 'package:zjxl_digital_user_center/src/user_center_config.dart';
export 'package:zjxl_digital_user_center/src/login/login_page.dart';
export 'package:zjxl_digital_user_center/src/pages_config.dart';
typedef UserCenterCallBack = Function(BuildContext context,dynamic response);
- 不建议使用new创建相关对象,直接对象加()就可以创建对象,
new Widget()与Widget()完全相同。 - 类、属性、方法的访问权限控制,如果不希望外部调用则设为私有,在开发过程中要将类、属性、方法的访问权限考虑进去,不能一味的全部开放,全部开发意味着外部调用方法和属性或初化类对象是可以正确操作和与你的设计是相符的。
class _AddBankCardPageState extends State<AddBankCardPage> {
BankCardModel _selectedCard;
ScrollController _scrollController = new ScrollController(); // listView 控制器
List<InputTextTileStyle> _inputTileStyles = [];
List<TextEditingController> _controllers = [];
TextEditingController _cardTypeController = TextEditingController(text: '对私');
TextEditingController _bankOfDepositController =
TextEditingController(text: '建设银行');
TextEditingController _cardNumberController = TextEditingController();
TextEditingController _ownerController = TextEditingController();
TextEditingController _idNumberController = TextEditingController();
TextEditingController _phoneNumberController = TextEditingController();
// 返回按钮点击,私有方法
void _leadingButtonClick() {
EasyLoading.dismiss();
Navigator.of(context).pop();
}
-
编码过程中习惯性使用“Reformat Code with dartfmt”,对编写的代码时进行整理
image.png
-
dispose()方法的释放资源;
class _QRScanCodeState extends State<QRScanCode> with TickerProviderStateMixin {
QRCaptureController _captureController = QRCaptureController();
Animation<Alignment> _animation;
AnimationController _animationController;
bool _isTorchOn = false;
bool _isPop = true;
String _captureText = '';
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_captureController.onCapture((data) {
print('onCapture----$data');
if (data != null) {
}
_captureText = data;
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animation =
AlignmentTween(begin: Alignment.topCenter, end: Alignment.bottomCenter)
.animate(_animationController)
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_animationController.reverse();
} else if (status == AnimationStatus.dismissed) {
_animationController.forward();
}
});
_animationController.forward();
}
- 实时处理报错(error)和警告(warning);
注释规范
- 单行注释,使用 // 或///;
///枚举命名采取大驼峰命名, 枚举值得采用小驼峰命名
enum BankCardListType {
myCard, // 我的银行卡列表
cleanType, // 结算对象银行卡列表
}
- 多行注释以 /* 开始, 以 */ 结束
/**
* uri: 请求接口时的uri(必填)
* requestId:本次请求的惟一id(必填)
* requestType: 请求类型,默认post
* headers:请求时head参数,传入时将会和公共head一块传入
* params: 请求的参数
*/
class BaseRequest {
Future sendRequest({
@required String uri,
@required String requestId,
RequestType requestType = RequestType.post
Map<String, dynamic> headers = const {},
Map<String, dynamic> params = const {},
bool isFormData = false,
}) {
GlobalRequestConfig config = GlobalConfigStorage.globalRequestConfig;
return this.sendRequestWithHostURI(
host: config.baseUrl,
uri: uri,
requestId: requestId,
jsonParams: jsonParams,
requestType: requestType,
isFormData: isFormData,
headers: headers,
params: params,
isShowLog: config.isShowLog,
timeout: config.timeout);
}
- 文档注释使用 ///, dart推荐的文档注释
/// ThemesManager 自定义主题使用方法:
/// 在main函数中监听 ThemesManager.instance
/// ```dart
/// Future<void> main() async {
/// runApp(
/// MultiProvider(
/// providers: [
/// ChangeNotifierProvider(
/// create: (_) => ThemesManager.instance,
/// )
/// ],
/// child: MyApp(),
/// )
/// );
/// }
/// ```
/// 在使用的区域 通过以下代码来获取当前的主题
/// ```dart
/// CustomThemeData currentTheme = context.watch<ThemesManager>().currentTheme;
/// 通过以下代码获取当前主题颜色,主题颜色参见CustomThemeData类
/// Color mainColor = currentTheme.mainColor;
///
/// 通过以下代码获取需要根据主题变换的图片,需要在主题的images目录中添加
/// Image icon = currentTheme.themeImage('cargo_icon_selected.png');
///
/// ```
///
class ThemesManager with ChangeNotifier{
/// 主题列表
List<CustomThemeData> _themes;
/// 当前主题
CustomThemeData _currentTheme;
int _currentThemeIndex = 0;
factory ThemesManager() =>_getInstance();
static ThemesManager get instance => _getInstance();
static ThemesManager _instance;
get currentThemeIndex{
return _currentThemeIndex;
}
ThemesManager._internal() {
_themes = List();
Theme1 theme1 = Theme1();
Theme2 theme2 = Theme2();
_themes.add(theme1);
_themes.add(theme2);
}
}
- 在新添加类文件顶部要添加开发者相关信息,格式如下
/** * 描述:注册时部上传位置SDK时的配置文件 * 作者:xxx * 建立时间: 2020/11/23 */ class RegisterConfig { /// 环境:“debug”测试,“release”正式,默认release(必填) final String environment; /// ios app bundleId,该bundleId须在交通部平台注册(必填) final String iosAppId; /// ios App 在交通部注册时的appSecurity(必填) final String iosAppSecurity; /// ios App 在交通部注册时的enterpriseSenderCode(必填) final String iosEnterpriseSenderCode; }
格式规范
组件开发规范
其他规范
markdown 文件编写帮助
https://maxiang.io/
https://shd101wyy.github.io/markdown-preview-enhanced/#/zh-cn/markdown-basics
网友评论