来源:Kinjal Dhamat
https://medium.com/flutter-community/flutter-best-practices-and-tips-7c2782c9ebb5
最佳实践是一个领域可以接受的专业标准,对于任何编程语言来说,提高代码质量、可读性、可维护性和健壮性都非常重要。
让我们探索一些设计和开发Flutter应用程序的最佳实践。
1. 命名规则
class
、 enum
、 typedef
和 extension
应采用驼峰命名 UpperCamelCase
规则。
class MainScreen { ... }
enum MainItem { .. }
typedef Predicate<T> = bool Function(T value);
extension MyList<T> on List<T> { ... }
类库、包、目录、以及源码文件都应使用带下划线的小写命名 lowercase_with_underscores
library firebase_dynamic_links;
import 'socket/socket_manager.dart';
变量、常量、参数和命名参数应都应使用小写字母开头的驼峰命名 lowerCamelCase
var item;
const bookPrice = 3.14;
final urlScheme = RegExp('^([a-z] ):');
void sum(int bookPrice) {
// ...
}
2. lib中的文件使用相对路径导入
当同时使用相对和绝对导入时,从两种不同的方式导入同一类时,可能会造成混乱。为了避免这种情况,我们应该对 lib/
文件夹中的文件使用相对路径导入
// Don't
import 'package:demo/src/utils/dialog_utils.dart';
// Do
import '../../../utils/dialog_utils.dart';
3. 指定变量类型
当值的类型已知时,请务必指定成员的类型,尽可能避免使用 var
//Don't
var item = 10;
final car = Car();
const timeOut = 2000;
//Do
int item = 10;
final Car bar = Car();
String name = 'john';
const int timeOut = 20;
4. 避免使用 as 作类型转换,应使用 is 运算符
通常,如果无法进行强制转换,使用 as
强制转换将会引发异常,为了避免异常,可以使用 is
//Don't
(item as Animal).name = 'Lion';
//Do
if (item is Animal)
item.name = 'Lion';
5. 使用 if 条件代替条件表达式
很多时候,我们需要根据条件渲染 Widget
,如果在条件表达式在任何情况下都返回 null
时,那么我们应该仅仅使用 if
条件
//Don't
Widget getText(BuildContext context) {
return Row(
children: [
Text("Hello"),
Platform.isAndroid ? Text("Android") : null,
Platform.isAndroid ? Text("Android") : SizeBox(),
Platform.isAndroid ? Text("Android") : Container(),
]
);
}
//Do
Widget getText(BuildContext context) {
return Row(
children:
[
Text("Hello"),
if (Platform.isAndroid) Text("Android")
]
);
}
6. 使用 ?? 和 ?. 操作符
优先使用 ??
(如果为 null
) 和 ?.
(可识别空值)运算符,而不是条件表达式中 null
检查
//Don't
v = a == null ? b : a;
//Do
v = a ?? b;
//Don't
v = a == null ? null : a.b;
//Do
v = a?.b;
7. 使用 spread 集合
当现有项目已经存储在另一个集合中时,spread 集合语法将使代码更简单
代码语言:javascript复制//Don't
var y = [4,5,6];
var x = [1,2];
x.addAll(y);
//Do
var y = [4,5,6];
var x = [1,2,...y];
8. 使用级联运算符
如果我们不想对同一对象执行一系列操作,则应使用级联运算符
代码语言:javascript复制// Don't
var path = Path();
path.lineTo(0, size.height);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0);
path.close();
// Do
var path = Path()
..lineTo(0, size.height)
..lineTo(size.width, size.height)
..lineTo(size.width, 0)
..close();
9. 使用原始字符串
原始字符串可用于避免转义字符带来的困扰
代码语言:javascript复制//Don't
var s = 'This is demo string \ and $';
//Do
var s = r'This is demo string and $';
10. 不要显式初始化变量 null
在 Dart 中,如果未指定变量的值,则变量会自动初始化为 null ,因此添加 null 是多余且不需要的
代码语言:javascript复制//Don't
int _item = null;
//Do
int _item;
11. 使用表达式函数体
对于仅包含一个表达式的函数,可以使用表达式函数
代码语言:javascript复制//Don't
get width {
return right - left;
}
Widget getProgressBar() {
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
);
}
//Do
get width => right - left;
Widget getProgressBar() => CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
);
12. 避免调用 print()
print()
和 debugPrint()
均用于打印日志到控制台,如果你使用 print()
并且一次输出太多内容,Android
有时会丢弃一些日志行,为了避免这种情况,请使用 debugPrint()
13. 拆分 Widget
当调用 setState()
,所有后代 Widget
都将重建,因此,将 Widget
拆分为小的 Widget
,在真正需要改变的 Widget
上调用 setState()
Scaffold(
appBar: CustomAppBar(title: "Verify Code"), // Sub Widget
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TimerView( // Sub Widget
key: _timerKey,
resendClick: () {})
],
),
),
)
14. 使用 ListView.builder 构建长列表
当使用无限列表或者非常大的列表时,通常建议使用 ListView.builder
以提高性能。
默认的 ListView
构造函数一次生成整个列表,ListView.builder
创建一个惰性列表,当用户向下滚动列表时,Flutter
会按需构建 Widget
15. 在 Widget 中使用 const
当 setState
调用时不会改变的 Widget
,我们应该将其定义为常量,这将阻止 Widget
重建,从而提高性能
Container(
padding: const EdgeInsets.only(top: 10),
color: Colors.black,
child: const Center(
child: const Text(
"No Data found",
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.w800),
),
),
);
我希望这些能给你一些见识,使你的 Flutter
代码更具可读性,同时也可以提高应用程序的性能。
编码愉快!