目录
Flutter中,声明式的视图样式代码 和 命令式的业务功能代码 混合编写,造成了书写代码时结构混乱,使得代码的嵌套层数过深,稍不留神便会写出“嵌套地狱”。
我的想法是利用Dart语言mixin和扩展函数,使Flutter的视图、功能和样式分离开,就像Vue一样能够清晰分为template/script/style三部分。让结构更明晰,以及减少嵌套。
首先,需要对所有窗口类(Widget)引入名为apply的扩展函数:
extension ApplyExt on Widget {
Widget apply(Function style){
return style.call(this);
}
}
类似于Kotlin的apply。这里的apply函数接受一个style函数为参数。style是一个以Widget为入参,并返回一个Widget的函数。在style函数中会对窗口进行诸如Padding、SizedBox和GestureDetector之类的包装。
例如,一个用来装饰标题文本的style函数可能会是这样(为与一般的方法区别,style函数命名用$开头):
Widget $title(Widget e) => Padding(
padding: const EdgeInsets.all(10),
child: SizedBox(
height: 40,
child: e,
),
);
style函数恰如Web前端中CSS,apply也可类比为class绑定。把样式归结为函数,就可以把样式从视图中分离,并实现样式的复用:
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("first line").apply($title),
Text("second line").apply($title),
Text("third line").apply($title),
],
);
}
}
同样地,一个文件的样式也能以style函数的形式被其它文件复用,甚至可以保存一些类似css文件的常用style函数库!而这些style函数正如css一样可以用于任何widget,不限于某一种widget!
我们还需要把功能和样式的代码部分从视图中分离。最起码,我们希望将视图(View)、功能(Method)和样式(Style)写在三个不同的“类”中。但在Dart中,使用混入(Mixin)会比使用类更合适。
Dart的Mixin能够将功能和样式的代码在视图所在的类之外的部分书写。
建两个Mixin,分别为Method和Style,将视图中用到的方法放到Method中,用到的样式函数放到Style,最后在视图所在的类中混入Method和Style即可。而视图所在的build函数中只需要写Column和Row这样的布局就行了!
例如,一个简单的计数器可以这样书写:
class CustomWidget extends StatefulWidget {
const CustomWidget({Key? key}) : super(key: key);
@override
CustomWidgetState createState() => CustomWidgetState();
}
//build函数中只写布局和窗口,并且在State类中混入Method和Style
class CustomWidgetState extends State<CustomWidget> with Method,Style{
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text("点击下面的按钮").apply($title),
IconButton(
icon: const Icon(Icons.add),
onPressed:(){setState((){increment();});},
).apply($button),
Text(countText).apply($countText)
],
);
}
}
//Method中写用到的功能函数、变量
mixin Method{
int _count = 0;
increment(){
_count++;
}
String get countText => "次数: $_count";
}
//Style中写样式函数,就像是写CSS一样
mixin Style{
$title(e) => Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: 300,
child: Center(
child: e,
),
)
);
$button(e) => SizedBox(
width: 100,
height: 50,
child: e,
);
$countText(e) => Padding(
padding: const EdgeInsets.symmetric(
vertical: 30,
),
child: e,
);
}
我们看到,整个Flutter代码被清晰地分成了三个部分(用首字母B-M-S作命名):
B:视图部分(Build函数)。所有的 行列布局 和 窗口 代码。
M:方法部分(Method混入)。视图中用到的方法、变量和计算变量。
S:样式部分(Style混入)。所有用来修饰窗口组件的样式函数。
这正好于Vue中<template>、<script>和<style>三个标签对应。也可以说,这是更具结构化的代码书写方式。
B-M-S模式的益处在于(B-Build,M-Method,S-Style):
然后,提供一个适用于Android Studio的实现该模式的代码模板:
class $NAME$ extends StatefulWidget {
const $NAME$({Key? key}) : super(key: key);
@override
State<$NAME$> createState() => $SNAME$();
}
class $SNAME$ extends State<$NAME$> with Method,Style{
@override
Widget build(BuildContext context) {
//build code here.
return Container($END$);
}
}
mixin Method on State<$NAME$>{
$NAME$ get prop => widget;
//method code here.
}
mixin Style on State<$NAME$>{
$NAME$ get prop => widget;
//style code here.
}
//SNAME : regularExpression(concat("_", NAME, "State"), "^__", "_")
这是我对Flutter中代码分离的探索,目的是更舒适地书写Flutter代码!
如果大家有相关的问题,或者更好的建议,欢迎评论区补充!
关于BMS,你可能还关心: