Flutter代码规范
插件推荐
为保证开发一致性,使用Android Studio
作为开发工具
Dart
Flutter
Flutter Intl
国际化FlutterAssetsGenerator
生成资源索引JsonToDart (JSON To Dart)
生成模型GetX
TinyPNG Image Optimizer
图片压缩Android Drawable Preview
图片图标预览Translation
翻译
代码规范
参考链接
主要注意一下几点
- 命名库、包、目录、dart文件都应该是小写加上下划线
library peg_parser/source_scanner;
import 'file_system.dart';
- 类, 枚举, 类型定义, 以及泛型,都需要使用大写开头的驼峰命名法
class HttpRequest { ... }
typedef Predicate<T> = bool Function(T value);
- 变量名、方法、参数名都应该是小写开头的驼峰命名法
HttpRequest httpRequest;
void align(bool clearItems) {}
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
- 内部类、方法、参数使用
_
开头
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
}
代码检查lints
- 使用官方flutter_lints及
analysis_options.yaml
文件配置,创建项目时会自动配置 - 编码过程中消除警告,查看Android Studio
Dart Analysis
面板消除警告后,编码基本符合Flutter及Dart的规范
git
- 使用Git Flow流程管理代码分支
项目规范
包管理
第三方包引用
引入第三方包,添加注释说明及库地址。防止库自动更新版本,版本号前面不使用^。
#网络请求 https://github.com/flutterchina/dio/blob/master/README-ZH.md
dio: 4.0.3
项目包引用
引用
目前一些常用的包以及自定义组件,我们使用library.dart
统一引入并导出
library library;
export 'dart:async';
export 'package:flutter/material.dart';
export 'package:flutter_screenutil/flutter_screenutil.dart';
export 'package:get/get.dart';
export 'package:common_utils/common_utils.dart';
...
减少包的引用,统一使用
import 'package:povison/common/library.dart';
类名冲突
import 'package:pokalive_flutter/common/library.dart' hide FormData;
import 'package:agora_rtc_engine/rtc_local_view.dart' as rtc_local_view;
项目框架结构
common公共基础包
utils工具类
net网络请求
net
├─net
│ ├─api 配置请求url,状态码
│ ├─exceptions 配置网络请求异常情况异常,如token已过期
│ ├─interceptors 配置网络拦截器,如抛出异常,baseUrl替换,显示Loading等功能
│ ├─options 配置网络请求额外的业务处理,如加解密、显示Toast/Loading
│ └─http.dart 基于Dio的包装类
ui
ui
├─style 颜色/主题
├─widgets 通用的widgets
│ ├─multi_state 多状态页面封装
│ └─refresh 刷新列表封装
generated
自动生成的文件
generated
├─assets 资源文件
└─I10n 国际化文件
models
存放Json模型
router
router
├─route 路由表配置
└─arguments 页面传参
ui
ui
├─pages 页面/逻辑
│ └─mian
│ ├─main_page 页面
│ └─main_logic logic
├─widgets 业务的widgets
资源处理
颜色/主题
class AppColors {
static const Color background = Color(0xFF0E0F1A);
static const Color transparent = Colors.transparent;
static const Color white = Colors.white;
static const Color black = Colors.black;
static const Color c333333 = Color(0xFF333333);
}
项目中使用
AppColors.c333333
//使用透明度
AppColors.c333333.withOpacity(0.5)
图片
图片生成
命名方式以对应功能/模块作为前缀 如 user_avater_cover
使用FlutterAssetsGenerator
插件自动生成Assets.dart
assets
├─image
│ ├─xx_tab_bg.dart
│ └─xx_tab_icon.dart
需要在pubspec.yaml
中配置目录
assets:
- assets/img/
项目中使用
Assets.imgPhEmpty
图片压缩
使用TinyPNG Image Optimizer
插件压缩图片,减少包体积
国际化
Flutter国际化 多语言 使用Flutter intl插件实现多语言
命名方式以对应功能/模块作为前缀 如 login_title
国际化配置文件intl_en.arb
{
"ph_empty": "Nothing is here",
"profile_call_coin": "{d} / Min",
"gift_tab_gift": "Gift ( [0] 1 = [1] 1 )",
}
一般使用
"ph_empty": "Nothing is here",
getString().ph_empty
有参数使用
"profile_call_coin": "{d} / Min",
getString().profile_call_coin(user.audioAmt!);
Span
当字符出现占位时,使用SpanUtil
进行处理
"gift_tab_gift": "Gift ( [0] 1 = [1] 1 )",
Text.rich(
TextSpan(
children: SpanUtil.formatRichText(
source: getString().gift_tab_gift,
spans: [
WidgetSpan(
child: Image.asset(Assets.userCoin, width: 10.w),
alignment: PlaceholderAlignment.middle,
),
WidgetSpan(
child: Image.asset(Assets.closeHeart, width: 10.w),
alignment: PlaceholderAlignment.middle,
),
],
),
)
) ;
Json to Dart
使用JsonToDart (JSON To Dart)
插件生成数据模型
一些组件的使用
状态管理Getx
相关资料
目前项目主要使用GetX的状态管理和路由管理
路由管理
///路由配置
class RouteConfig {
///主页
static const String main = "/main";
static final List<GetPage> getPages = [
GetPage(
name: main,
page: () => MainPage(),
),
];
}
//定义页面传参规范
class MainPageArguments {
final String value;
MainPageArguments(this.value);
}
页面跳转与参数传递,参数获取
var result = await Get.toNamed(RouteConfig.main,arguments: MainPageArguments("value"));
//do something
class OrderDetailLogic extends MultiStateLogic {
var orderDetail = OrderDetail().obs;
@override
Future initData() {
if (Get.arguments is OrderDetailPageArguments) {
OrderDetailPageArguments arguments = Get.arguments;
//do something
}
}
}
状态管理
通过Getx
插件生成一个文件夹,包含logic和page文件,分别处理逻辑和UI
pages
├─xx
│ ├─xx_logic.dart
│ └─xx_page.dart
页面展示
一般根据网络请求的成功与否,页面通常有Loding/Success/Empty/Error等状态,需要对页面结构封装,自动处理状态展示及点击重试
本项目使用了Getx的状态,可以实现状态页面懒加载,参考使用GetX构建更优雅的页面结构
一般页面
项目封装了MultiStateWidget
作为页面状态的Widget,搭配MultiStateLogic
使用
class OrderDetailPage extends StatelessWidget {
final logic = Get.put(OrderDetailLogic());
OrderDetailPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const NaviAppBar(title: 'Order Detail'),
backgroundColor: AppColors.cF9F9F9,
body: MultiStateWidget(
logic: logic,
content: SingleChildScrollView(
child: Obx(() {
return Column(
children: [
...
],
);
}),
),
),
);
}
)
class OrderDetailLogic extends MultiStateLogic {
var orderDetail = OrderDetail().obs;
@override
Future initData() async {
if (Get.arguments is OrderDetailPageArguments) {
OrderDetailPageArguments arguments = Get.arguments;
orderDetail.value = await HttpManager.orderDetail(arguments.orderId);
}
}
}
列表页面
进一步封装,使用RefreshListView
和RefreshListLogic
class HomePage extends StatelessWidget {
final logic = Get.put(HomeLogic());
HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RefreshListView(
logic: logic,
itemBuilder: itemBuilder,
);
}
class HomeLogic extends RefreshListLogic<Showcase> {
@override
Future<List<Showcase>> load(int pageNo) async {
return await HttpManager.getHome();
}
@override
int get pageSize => 0;
}
网络请求
ApiUrl
统一配置管理
class ApiUrl {
static const baseUrl = Config.testUrl ? "https://test-api.pokalive.com/" : "https://www.povison.com/";
///登录
static const login = 'front/member/login';
}
HttpManager
管理相关的网络请求及Json转换
class HttpManager {
static Future<List<Showcase>> getHome() async {
var response = await Http().get(
ApiUrl.home,
options: HttpOptions.getOptions(showLoading: true),
);
HomeResult homeResult = HomeResult.fromMap(response.data);
return homeResult.data;
}
}