前言
良好的规范让你的代码不仅看上来更简洁,也让你的代码更加具有可读性,及大大的减少了后期维护的成本。
以下从几个方面谈谈我对Flutter良好的规范的理解。
一、页面Page规范前后效果对比
我们先从页面开始(以登录页的优化为例),然后逐步的从点到面铺开描述。
目标:页面布局、控件定义、事件处理分离。
1、演示的Page的UI图

2、规范前的效果
规范前:未进行任何处理的时候,你的代码是这样的。

3、规范后的效果
规范后**:按规范处理后你代码的效果是这样的,

可见通过处理后Page的整体代码更加简洁了。
二、页面Page开发规范的细则
写:

不写:

写法如下:

如此通过以上两步后,Widget build中的代码即会变为如下:

如此通过以上几个拆分,我们的Page页面就显得很简洁和很好维护了。
细心的你,可能发现了我们这里有一个系统没有的LoginTextField文本框类。是的,该类是我们自定义封装到Package后来使用的。
对于一个控件怎么封装,详情查看之前的文章《Flutter进阶(2):控件Widget的自定义与封装》
三、页面Page规范小结
在*build方法里尽量用最少的代码实现整体视图。如下,我们将登录页中的所有Widget通过loginWidgets()*函数封装起来。
在*loginWidgets()方法里实现页面Widgets的布局。而对于Widget的定义为了不让页面布局与控件定义因写在一堆,而造成代码一大坨。我们对每个Widget单独提供定义的函数,如userNameTextField()*即为定义用户文本框的函数。
3、抽离每个Widget的定义
4、封装单个Widget
四、业务逻辑的开发规范
说完了页面上的Widgets的开发规范,下面就轮到页面上的业务逻辑的开发规范了。
拿登录页需要获取上次登录的账号来说,它的业务是getDefaultLoginAccountAction,下面以混编时候的项目为例
1、未去解耦业务时候的登录页
getDefaultLoginAccountAction在Page中的实现一般为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| static const callNativeMethodChannel = const MethodChannel('com.dvlproad.ciyouzen/callNativeLoginMethodChannel'); Future<Null> _getDefaultLoginAccountAction() async { try { final Map nativeResponse = await callNativeMethodChannel.invokeMethod('getDefaultLoginAccountAction'); final Map nativeResult = callNativeNativeResult(nativeResponse);
setState(() { userName = nativeResult["userName"]; password = nativeResult["password"]; print(userName + ":" + password); _usernameController.text = userName; _passwordController.text = password; }); } on PlatformException {} }
|
相应的它的调用为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyLoginPage extends StatefulWidget { MyLoginPage({Key key, this.title}) : super(key: key);
final String title;
@override _MyLoginPageState createState() => _MyLoginPageState(); }
class _MyLoginPageState extends State<MyLoginPage> { @override void initState() { super.initState(); print("Login Page initState");
_getDefaultLoginAccountAction(); } }
|
可见上述的业务处理getDefaultLoginAccountAction中,掺杂了对页面Page的setState操作,这不适合我们以后只对业务或者只对页面做修改的处理。所以下面我们将它们解耦。
2、解耦业务时候的登录页

getDefaultLoginAccountAction在ChannelModel中的实现一般为:
1 2 3 4 5 6 7 8 9 10 11
| Future<Map<String, dynamic>> getDefaultLoginAccountAction() async { try { final Map nativeResponse = await callNativeMethodChannel.invokeMethod('getDefaultLoginAccountAction'); final Map nativeResult = callNativeNativeResult(nativeResponse);
return nativeResult; } on PlatformException { return null; } }
|
相应的它的调用为:
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
| class MyLoginPage extends StatefulWidget { MyLoginPage({Key key, this.title}) : super(key: key);
final String title;
@override _MyLoginPageState createState() => _MyLoginPageState(); }
class _MyLoginPageState extends State<MyLoginPage> { @override void initState() { super.initState(); print("Login Page initState");
getDefaultLoginAccountAction().then((nativeResult){ setState(() { userName = nativeResult["userName"]; password = nativeResult["password"]; print(userName + ":" + password); _usernameController.text = userName; _passwordController.text = password; }); }); } }
|
五、Flutter Channel的数据规范
在使用Flutter与原生项目混编的时候,因为涉及到数据传输,所以我们有必要在前期就对传输数据的进行规范统一。