Flutter Widget源码解析及实战(一)

简介: Flutter Widget源码解析及实战(一)

Widget


在flutter中所有页面展示出来的元素都是由一个个的widget组成,与原生android开发不同的地方在于flutter中widget不仅仅表示UI元素,他也可以是一个完全和UI无关如GestureDetector,GestureDetector继承自StatelessWidget。


Widget的功能类似于原生android开发中的style文件,用来描述UI的样式,最终真正绘制在屏幕上的是Element。

@immutableabstract class Widget extends DiagnosticableTree { // DiagnosticableTree 诊断树主要作用是提供调试信息    const Widget({ this.key }); // key 
  // 最终整个绘制流程在Element中进行  @protected  Element createElement();
  @override  String toStringShort() {    return key == null ? '$runtimeType' : '$runtimeType-$key';  }
  // 提供一些调试用的信息  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;  }
  // 这里通过判断key和runtimeType是否一致来判断是否可以更新UI  static bool canUpdate(Widget oldWidget, Widget newWidget) {    return oldWidget.runtimeType == newWidget.runtimeType        && oldWidget.key == newWidget.key;  }}


StatelessWidget


无状态的widget一般用于一些静态UI的绘制(例如:Text)或者提供与UI无关的功能(例如:GestureDetector用来管理手势相关的功能),源码如下:


abstract class StatelessWidget extends Widget {    const StatelessWidget({ Key key }) : super(key: key);    @override  StatelessElement createElement() => StatelessElement(this);    @protected  Widget build(BuildContext context);  }


StatelessWidget用于不需要维护状态的场景,它通常在build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget,具体如下:


class TestLess extends StatelessWidget {  @override  Widget build(BuildContext context) {    return Container(      child: Text("test"),    );  }}

StatefulWidget


可变状态的小部件

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
  @override  StatefulElement createElement() => StatefulElement(this);
  @protected  State createState();}


与StatelessWidget不同的是StatefulWidget类中添加了一个新的接口createState(),一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态。下面是StatefulWidget的最佳实践:


  • 尽量将需要该表状态的widget防止在子节点,这样在改变整个渲染树的时候就只需要更新一个widget即可,如果将其防止在父节点那么将会导致当前节点的整个子节点的widget都会被重新渲染。
  • 尽量减少build方法中返回的widget的嵌套层级,理想情况下一个StatefulWidget仅仅只包含一个类型为RenderObjectWidget的子widget。例如:RichText,但显然这是不切实际的,但一个小部件越是接近这个理想,效率越高。
  • 如果子树没有更改,请缓存表示该子树的窗口小部件,并在每次使用时重新使用它。对于要重新使用的窗口小部件,要比创建新的(但配置相同的)窗口小部件更有效。将有状态部分分解为带有子参数的小部件是执行此操作的常用方法。
  • 尽可能使用`const`小部件。(这相当于缓存窗口小部件并重新使用它。)
  • 避免更改任何创建的子树的深度或更改子树中任何窗口小部件的类型。例如,不是返回包含在[IgnorePointer]中的子项或子项,而是始终将子窗口小部件包装在[IgnorePointer]中并控制[IgnorePointer.ignoring]属性。这是因为更改子树的深度需要重建,布局和绘制整个子树,而只更改属性将需要对渲染树进行尽可能少的更改(例如,在[IgnorePointer]的情况下,没有布局)或重绘是必要的)。
  • 如果由于某种原因必须更改深度,请考虑将子树的公共部分包装在具有[GlobalKey]的小部件中,该[GlobalKey]在有状态小部件的生命周期内保持一致。(如果没有其他小部件可以方便地分配密钥,[KeyedSubtree]小部件可能对此有用。)


下面是一个名为`YellowBird`的有状态小部件子类的框架。在这个例子中[State]没有实际状态。State通常表示为私人成员字段。此外,通常小部件有更多的构造函数参数,每个参数都应该为`final`类型。

class YellowBird extends StatefulWidget {   const YellowBird({ Key key }) : super(key: key);
   @override   _YellowBirdState createState() => _YellowBirdState(); }
 class _YellowBirdState extends State<YellowBird> {   @override   Widget build(BuildContext context) {     return Container(color: const Color(0xFFFFE306));   } }


下面的例子显示了更通用的小部件`Bird`,它可以被赋予一种颜色和一个子widget,并且它有一些内部状态,可以调用一个方法来改变它。

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

按照惯例,窗口小部件构造函数仅使用命名参数。可以使用[@required]将命名参数标记为必需。按照惯例,第一个参数是[key],最后一个参数是`child`,`children`。


StatefulWidget生命周期


image.png

State中有两个常用属性


  • widget  :表示与State实例相关联的widget实例
  • BuildContext:构建widget的上下文
  • initState:当Widget第一次插入到Widget树时会被调用,对于每一个State对象。framework将在创建的每个[State]对象调用此方法一次。重写此方法以执行初始化,该初始化取决于此对象插入树中的位置(即[context])或用于配置此对象的窗口小部件(即[widget])。如果[State]的[build]方法依赖于一个本身可以改变状态的对象,例如[ChangeNotifier]或[Stream],或者一个可以订阅接收通知的其他对象,那么一定要订阅并在[initState],[didUpdateWidget]和[dispose]中取消订阅:您不能使用此方法中的[BuildContext.inheritFromWidgetOfExactType]。但是,[didChangeDependencies]将在此方法之后立即调用,可以在那里使用[BuildContext.inheritFromWidgetOfExactType]。
  • didChangeDependencies:当State对象的依赖发生变化时会被调用,如果父Widget重建并请求树中的此位置更新以显示具有相同[runtimeType]和[Widget.key]的新Widget,则框架将更新此[State]对象的[widget]属性以引用新Widget然后使用上一个Widget作为参数调用此方法。覆写此方法可以在[widget]更改时进行响应(例如,开始隐式动画)。在调用[didUpdateWidget]之后,框架总是调用[build],这意味着对[didUpdateWidget]中的[setState]的任何调用都是多余的。
  • build:它主要是用于构建Widget子树
  • reassemble:此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用。
  • didUpdateWidget:在widget重新构建时,framework会调用canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新。
  • deactivate:当State对象从树中被移除时,会调用此回调。在一些场景下,Flutter framework会将State对象重新插到树中,如包含此State对象的子树在树的一个位置移动到另一个位置时(可以通过GlobalKey来实现)。如果移除后没有重新插入到树中则紧接着会调用dispose()方法。
  • dispose:当State对象从树中被永久移除时调用;通常在此回调中释放资源。
相关文章
|
4月前
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
193 27
|
4月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
403 29
|
4月前
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
299 4
JSON数据解析实战:从嵌套结构到结构化表格
|
4月前
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
154 4
|
4月前
|
机器学习/深度学习 人工智能 Java
Java机器学习实战:基于DJL框架的手写数字识别全解析
在人工智能蓬勃发展的今天,Python凭借丰富的生态库(如TensorFlow、PyTorch)成为AI开发的首选语言。但Java作为企业级应用的基石,其在生产环境部署、性能优化和工程化方面的优势不容忽视。DJL(Deep Java Library)的出现完美填补了Java在深度学习领域的空白,它提供了一套统一的API,允许开发者无缝对接主流深度学习框架,将AI模型高效部署到Java生态中。本文将通过手写数字识别的完整流程,深入解析DJL框架的核心机制与应用实践。
223 3
|
4月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
124 4
|
4月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
4月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
4月前
|
缓存 监控 搜索推荐
【实战解析】smallredbook.item_get_video API:小红书视频数据获取与电商应用指南
本文介绍小红书官方API——`smallredbook.item_get_video`的功能与使用方法。该接口可获取笔记视频详情,包括无水印直链、封面图、时长、文本描述、标签及互动数据等,并支持电商场景分析。调用需提供`key`、`secret`和`num_iid`参数,返回字段涵盖视频链接、标题、标签及用户信息等。同时,文章提供了电商实战技巧,如竞品监控与个性化推荐,并列出合规注意事项及替代方案对比。最后解答了常见问题,如笔记ID获取与视频链接时效性等。
|
4月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多
  • DNS