在Flutter开发中,我们会经常和各种控件打交道,它们也能满足业务的大部分需求。但是,我们往往需要将多个控件组合起来,才能实现业务的需求,而且这样写出来的代码维护起来非常困难。因此,我们可以把那些需要多个控件组合才能实现的功能自定义化,成为一个自定义控件,易于维护。

无状态控件

Flutter框架给我们提供了StatelessWidget和StatefulWidget两个抽象类,用于自定义控件,首先我们看一下StatelessWidget抽象类。它可以定义一个不需要可变状态的控件,我们可以称其为“无状态控件”,它通过构建一系列其他控件来描述用户界面的一部分,构建过程以递归方式执行,直到用户界面的描述完全具体化。

比如,下面是一个名为“GreenBoard”的StatelessWidget子类的框架,它的里面包括一个Container控件,中文名称是“容器”,然后设置color属性,也就是背景色为绿色。

class GreenBoard extends StatelessWidget {const GreenBoard({ Key key }) : super(key: key);@overrideWidget build(BuildContext context) {return new Container(color: const Color(0xFF2DBD3A));}
}

上面代码中,应用了《Dart入门—类与方法》的知识,大家可以去简单了解下。另外,我们覆盖了build这个抽象方法,该方法用于描述由此控件所实现的那一部分用户界面。其中,抽象类BuildContext是该控件在控件树中的位置句柄。

通常情况下,控件的构造函数参数不止一个,每个参数对应一个final修饰的属性,修改上一个例子,使其成为一个可以设置背景颜色和子控件的通用控件。

class Board extends StatelessWidget {const Board({Key key,this.color: const Color(0xFF2DBD3A),this.child,}) : super(key: key);final Color color;final Widget child;@overrideWidget build(BuildContext context) {return new Container(color: color, child: child,);}
}

按照Flutter框架的语法规范,控件的构造函数只能使用命名参数,命名参数可以使用@required注解为必需参数。另外语法规范还规定了,第一个参数是key,最后一个参数是childchildren或其他类似参数。

如果一个无状态控件的父控件会定期更改控件的配置,或者它依赖于频繁更改的继承控件,那么优化build方法的性能,以保持流畅的渲染性能是非常重要的。有以下做法可以用于减少重新构建无状态控件的影响:

  • 尽可能减少build方法传递创建的节点数量及其创建的任何控件。例如,我们可以考虑只使用Align(对齐控件)或CustomSingleChildLayout(自定义单个子控件布局控件),而不是精心安排Row(行布局控件)、Column(列布局控件)、Padding(填充控件)和SizedBox(指定大小的框控件)来定位单个子控件。想绘制正确的图形效果时,考虑一下使用CustomPaint(画布控件),而不是复杂的多个Container(容器)分层和Decoration(装饰)。
  • 尽可能使用const修饰控件,并为控件提供一个const构造函数,以便控件的调用方法也可以这样做。

有状态控件

在了解完如何使用StatelessWidget定义一个无状态控件后,我们学习如何使用StatefulWidget定义一个具有可变状态的控件,我们可以称其为“有状态控件”。首先要搞清楚的是,状态是什么?状态是在构建控件时可以同步读取的信息,并且在控件的生命周期内可以改变,控件的使用者应该在状态发生变化时使用State.setState方法及时通知框架。

StatefulWidget的实例本身是不可变的,我们需要将其可变状态存储在由createState方法创建的单独的State对象中,或者存储在该State所订阅的对象中。例如,我们将之前名为“GreenBoard”的StatelessWidget子类改造成StatefulWidget的子类框架。

class GreenBoard extends StatefulWidget {const GreenBoard({ Key key }) : super(key: key);@override_GreenBoardState createState() => new _GreenBoardState();
}class _GreenBoardState extends State<GreenBoard> {@overrideWidget build(BuildContext context) {return new Container(color: const Color(0xFF2DBD3A));}
}

只要我们调用了一个StatefulWidget,框架就会调用createState,这意味着,在控件树中,可能有多个不同位置的State对象与同一个StatefulWidget关联。同样的,如果一个StatefulWidget被我们从树中移除,并且再次被我们插入到树中,框架将再次调用createState来创建一个新的State对象,简化了State对象的生命周期。

我们再将之前名为“Board”的StatelessWidget子类改造成StatefulWidget的子类框架。除了可以设置背景颜色和子控件,还有一个可以被调用的,用来改变它的内部状态的方法。

class Board extends StatefulWidget {const Board({Key key,this.color: const Color(0xFF2DBD3A),this.child,}) : super(key: key);final Color color;final Widget child;_BoardState createState() => new _BoardState();
}class _BoardState extends State<Board> {double _size = 1.0;void grow() {setState(() { _size += 0.1; });}@overrideWidget build(BuildContext context) {return new Container(color: widget.color,transform: new Matrix4.diagonal3Values(_size, _size, 1.0),child: widget.child,);}
}

StatefulWidget有两种不同的类型:

  • 第一种是在State.initState中分配资源并将其置于State.dispose中,而且不依赖于InheritedWidget或调用State.setState。这样的控件通常在应用程序或页面的根部使用,并通过ChangeNotifier、Stream或其他这样的对象与子控件通信。遵循这种模式的有状态控件相对便宜(在CPU和GPU周期方面),因为它们是一次构建的,而且不会更新。因此,它们可以实现一些非常复杂的build方法。
  • 第二种是使用State.setState或依赖于InheritedWidget的控件。这些控件通常会在应用程序的生命周期中重新构建很多次,因此降低重新构建这种控件的影响至关重要。实际上,它们也可以使用State.initState或State.didChangeDependencies来分配资源,但重点是它们要重新构建。

有以下做法可以用于减少重新构建有状态控件的影响:

  • 把状态推到树叶上。例如,我们的页面上有一个嘀嗒嘀嗒的时钟,此时不应该将状态置于页面的顶部,因为这样的话,每当时钟嘀嗒时,整个页面都会重新构建。我们应该创建一个专用的时钟控件,这样只会更新它自己。
  • 尽可能减少build方法传递创建的节点数量及其创建的任何控件。理想情况下,有状态的控件只会创建一个控件,而这个控件将是一个RenderObjectWidget。很显然,在实际开发中,我们不一定能做到这一点,但控件越接近这个理想状态,效率就越高。
  • 如果子树不更改,则缓存表示该子树的控件,并在每次使用该子树时重新使用它。重用控件的效率要比创建新的控件要高效得多,将有状态的部分分解成一个带有子参数的控件是这样做的常见方法。
  • 尽可能使用const修饰控件,这相当于缓存一个控件,并重新使用它。

关于有状态与无状态的选择

如果自定义的控件可以与用户进行交互,比如通过键盘输入内容、通过滑动屏幕移动滑块、点击时改变状态,又或者是随着时间的推移而变化,比如数据Feed会更新状态。这时我们应该选择使用StatefulWidget创建一个有状态控件。

如果自定义的控件仅依赖于对象本身的配置信息,仅仅是用于展示给定的信息。那我们应该选择使用StatelessWidget创建一个无状态控件。

自定义Flutter控件相关推荐

  1. Flutter 自定义UI控件并设置交互能力

    1.自定义UI控件 首先UI控件按照是否能够与用户交互分为交互型控件和非交互型控件. 下面就是创建了一个交互型控件,只是关于界面是空的,如果我们继承StatelessWidget就是创建了一个非交互型 ...

  2. Flutter控件--Switch 和 SwitchListTile

    flutter控件练习demo地址:github Switch(开关).SwitchListTile(带标题的开关) 和 AnimatedSwitch 一 Switch 1.1 简介 Switch & ...

  3. Android 手机卫士--自定义组合控件构件布局结构

    由于设置中心条目中的布局都很类似,所以可以考虑使用自定义组合控件来简化实现 本文地址:http://www.cnblogs.com/wuyudong/p/5909043.html,转载请注明源地址. ...

  4. Android View体系(十)自定义组合控件

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

  5. iOS自定义View 控件自动计算size能力

    iOS自定义View 控件自动计算size能力 背景 在使用 UILabel 和 UIImage 的时候,不用指定宽高约束,控件也不会报约束缺失,还可以根据内容自己确定适合的宽高,特别适合 Xib 和 ...

  6. VS2010 自定义用户控件未出现在工具箱的解决方案

    VS2010 自定义用户控件未出现在工具箱的解决方案 参考文章: (1)VS2010 自定义用户控件未出现在工具箱的解决方案 (2)https://www.cnblogs.com/lyout/arch ...

  7. [置顶] 分步实现具有分页功能的自定义DataList控件【附源代码】

    一.控件也是类 [效果] [操作步骤] 1.  新建网站Web 2.  添加类CustomDataList.cs(系统会提示你把类建在App_Code文件夹中),代码如下: using System; ...

  8. [转] 使用模板自定义 WPF 控件

      [转] 使用模板自定义 WPF 控件                                                                                 ...

  9. 自定义组合控件:下拉选择框

    Spinner 自定义组合控件之下拉选择框 项目概述 下拉选择框主要是通过在EditText 下用PopupWindow 动态显示ListView 控件来实现的.下拉选择框可以方便用户的输入效率,以此 ...

最新文章

  1. 如何用数据结构解释计算机系统 常用数据结构
  2. CICC科普栏目|颠覆认知!看完这些图,你的世界观还好吗?
  3. ubuntu pip
  4. 图像处理之 opencv 学习---opencv 中的常用算法
  5. 关于idea右侧的maven project 如何调出来
  6. 15-description-Objective-C笔记
  7. Android Studio之debug调试卡在waiting for debugger界面的解决办法
  8. 项目部署到weblogic后页面乱码问题
  9. python随机函数random求最大值_Python遗传算法求一元函数最大值
  10. C++ vector 容器的使用
  11. TreeView和Menu
  12. java高级-反射的三种实例化模式及与工厂,单例模式的的关系
  13. 【2019南昌邀请赛网络赛 B Greedy HOUHOU BZOJ 2957 楼房重建】线段树+二分
  14. 345.反转字符串中的元音字符(力扣leetcode) 博主可答疑该问题
  15. html 滑动门效果,js实现简洁的滑动门菜单(选项卡)效果代码
  16. 计算机组成原理第五章----存储器容量的扩展与芯片连接
  17. nb-iot信号测试软件,NB-IOT测试仪
  18. TortoiseGit文件夹及文件图标不显示解决方法
  19. R星安装不完全无法载入social club(错误码:1)解决办法
  20. 六面蚂蚁金服,唬住了面试官要了 30K;其实 Java 面试也没那么难

热门文章

  1. Parencodings 模拟
  2. LeetCode:62. 不同路径(python、c++)
  3. AcWing.282石子合并(区间DP)题解
  4. 错排问题(以航电OJ 2048 为例)
  5. 实验5.2 动态内存分配生成动态数组完成矩阵转置
  6. 1936 问题 B: 打印极值点下标(C语言)
  7. 计算机视觉(CV)中HOG算法的主要步骤
  8. Matlab语音倍速播放
  9. python tkinter中的锚点(anchor)问题
  10. leetcode185 Department Top Three Salaries