目录

1.引入apply函数

2.用Mixin分离Method和Style

3.总结:BMS模式


Flutter中,声明式的视图样式代码 和 命令式的业务功能代码 混合编写,造成了书写代码时结构混乱,使得代码的嵌套层数过深,稍不留神便会写出“嵌套地狱”。

我的想法是利用Dart语言mixin和扩展函数,使Flutter的视图、功能和样式分离开,就像Vue一样能够清晰分为template/script/style三部分。让结构更明晰,以及减少嵌套。

1.引入apply函数

首先,需要对所有窗口类(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});@overrideWidget 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!

2.用Mixin分离Method和Style

我们还需要把功能和样式的代码部分从视图中分离。最起码,我们希望将视图(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);@overrideCustomWidgetState createState() => CustomWidgetState();
}//build函数中只写布局和窗口,并且在State类中混入Method和Style
class CustomWidgetState extends State<CustomWidget> with Method,Style{@overrideWidget 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>三个标签对应。也可以说,这是更具结构化的代码书写方式。

3.总结:BMS模式

B-M-S模式的益处在于(B-Build,M-Method,S-Style):

  • 极大程度上减小了代码嵌套。原本的视图被分为了三个部分。最为繁琐的样式已经被纳入Style混入组件中,且可以被apply函数复用。只需要在build函数中写视图中行与列的布局,和窗口的初始化,其余的样式都是用类似Web前端中class绑定的方式(apply函数)引入的。
  • 代码更加结构化。一个组件的构建被严格地划分为了视图、方法和样式。不必将函数功能代码混写到视图代码中。在设计组件时可以采取 视图→样式→方法 的逻辑顺序。
  • 没有引入框架或依赖,完全基于Dart原有的语法。唯一的改动是增加了一个不到5行的apply函数。因为是完全基于Dart语法,故可轻松与一般的代码写法结合与转换,也可随时引入Provider等框架。

然后,提供一个适用于Android Studio的实现该模式的代码模板:

class $NAME$ extends StatefulWidget {const $NAME$({Key? key}) : super(key: key);@overrideState<$NAME$> createState() => $SNAME$();
}class $SNAME$ extends State<$NAME$> with Method,Style{@overrideWidget 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,你可能还关心:

如何让apply能传入多个style参数?如何动态绑定样式?

Flutter中实现视图、功能和样式代码的分离(使用mixin与扩展函数)相关推荐

  1. Flutter中文本输入框TexeFieldr键盘样式TextInputType总结TexeField设置不可编辑

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. TextField 系列文章 TextField的基本使用以及TextField常用属性精讲<点击查看详情> ...

  2. android中截屏功能实现,android代码实现截屏功能

    android开发中通过View的getDrawingCache方法可以达到截屏的目的,只是缺少状态栏! 原始界面 截屏得到的图片 代码实现 1. 添加权限(AndroidManifest.xml文件 ...

  3. 快速复制网站中的html与css样式代码

    原理:把整个网页中元素的样式全部改为内连样式. 使用方式: 1.打开浏览器控制台. 2.运行以下脚本. 3.复制控制台输出. 4.新建一个html 文件,将复制的内容copy 到这个文件中. 5.浏览 ...

  4. java发邮件的框架_Java的Spring框架中实现发送邮件功能的核心代码示例

    Spring中已经封装了邮件操作类,通过spring配置文件可以便捷地注入到controller.action等地方. 下面是配置: p:host="${mail.host}" p ...

  5. java邮件模板代码_Java的Spring框架中实现发送邮件功能的核心代码示例

    Spring中已经封装了邮件操作类,通过spring配置文件可以便捷地注入到controller.action等地方. 下面是配置: p:host="${mail.host}" p ...

  6. flutter 中实现磨砂玻璃效果

    flutter 中实现磨砂玻璃效果 前言 磨砂玻璃效果是一个很酷的用户界面概念,使我们的用户界面看起来更有吸引力.它基本上是一个模糊的覆盖与减少不透明度,以区分或减少某一观点.这个功能看起来确实不错, ...

  7. flutter中的生命周期

    前言 和其他的视图框架比如android的Activity一样,flutter中的视图Widget也存在生命周期,生命周期的回调函数提现在了State上面.理解flutter的生命周期,对我们写出一个 ...

  8. js php通讯录,基于aotu.js实现微信自动添加通讯录中的联系人功能

    什么是Auto.JS? Auto.JS是Android平台上的JavaScript自动化工具. 它的本质是可执行自己编写的简易Javascript脚本的,尤其可以在开启"无障碍模式" ...

  9. android中NFC读写功能的实现方法

    这篇文章主要为大家详细介绍了android中NFC读写功能的实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了android中NFC读写功能的 ...

最新文章

  1. SpringJpa多对多映射关系
  2. 王瑜琪:数据科学助力我捕捉研究生教育的宏观效应 | 提升之路系列
  3. linux怎么离线安装gcc文件夹,CentOS下离线安装gcc环境,图文详细,方法全面
  4. Git常见报错及解决方法
  5. php 数据显示格式,php数据格式
  6. 你还在担心开车看不到路标吗?我这这有个路标分类的来玩玩啊(有源码有数据集)
  7. Elasticsearch基础(一)mapping
  8. lightgbm过去版本安装包_谨慎更新华为EMUI10.1版本
  9. OpenDaylight Hydrogen版本应用SampleTap研究(一)
  10. WebService框架简介
  11. Django使用Channels实现WebSSH网页终端,实现SSH堡垒机雏形
  12. 元学习入门必备:MAML(背景+论文解读+代码分析)
  13. 李笑来深夜宣布不做个人投资,背后有何深意?
  14. 质数距离 数论(线性筛选素数 合数存在素数因子)
  15. 京东跨端组件库 NutUI 2.0 来袭
  16. Kaggle系列-Tweet Sentiment Extraction第一名方案
  17. 焊缝标注vlx实用程序_机械制图焊缝标注方法!太全了,收藏了
  18. 【UFUN开发板评测】小巧而不失精致,简单而不失内涵——uFun开发板开箱爆照...
  19. ros开发增加clion常用模板及初始化配置(二)
  20. 赴一场心仪已久的戴尔中国“家宴”

热门文章

  1. Ubuntu 16.04 amd64架构下安装使用i386程序动态链接库依赖
  2. Mac下的tar、zip、gz解压
  3. 如何在 ios 的浏览器或者 微信 唤起 app-store,如何检测是否有安装该app
  4. 漂移板初级进阶讲解(精编)
  5. N97连接WIFI提示预置共享密钥无效
  6. 《神经网络与深度学习》-概率图模型
  7. JAVA计算机毕业设计垃圾分类网站Mybatis+系统+数据库+调试部署
  8. 使用uniapp 开发微信小程序map组件在开发过程中遇到的问题
  9. this.$refs 为空问题
  10. 理解 t != (t = tail)