Flutter之build 方法详解

前言

我们创建一个Flutter程序,入口文件内容如下

//导包,此行代码作用是导入了 Material UI 组件库。Material (opens new window)是一种标准的移动端和 web 端的视觉设计语言, Flutter默认提供了一套丰富的 Material 风格的 UI 组件。
import 'package:flutter/material.dart';

//应用入口
void main() {
  runApp(const MyApp());
}

/// 在 Flutter 中,大多数东西都是 widget(后同“组件”或“部件”),包括对齐(alignment)、填充(padding)和布局(layout)等,它们都是以 widget 的形式提供。
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override

  ///Flutter 在构建页面时,会调用组件的build方法,widget 的主要工作是提供一个 build()方法来描述如何构建 UI 界面(通常是通过组合、拼装其它基础 widget)。
  Widget build(BuildContext context) {
    ///MaterialApp 是 Material 库中提供的 Flutter APP 框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等。MaterialApp也是一个 widget。
    return MaterialApp(
      //用于名称
      title: 'Flutter Demo',
      //主题
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      //home 为 Flutter 应用的首页,它也是一个 widget。
      home: const MyHomePage(title: 'Flutter Demo  Page'),
    );
  }
}

//首页 它继承自StatefulWidget类,表示它是一个有状态的组件(Stateful widget)
class MyHomePage extends StatefulWidget {
  //required 代表着title必须传入
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    //setState方法的作用是通知 Flutter 框架,有状态发生了改变,Flutter 框架收到通知后,会执行build方法来根据新的状态重新构建界面, Flutter 对此方法做了优化,使重新执行变的很快,所以你可以重新构建任何需要更新的东西,而无需分别去修改各个 widget
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    //Scaffold 是 Material 库中提供的页面脚手架,它提供了默认的导航栏、标题和包含主屏幕widget树(后同“组件树”或“部件树”)的body属性,组件树可以很复杂。路由默认都是通过Scaffold创建。
    return Scaffold(
      //顶部导航栏
      appBar: AppBar(
        // 这里,我们从App.build方法创建的MyHomePage对象中获取值,并使用它设置appbar标题。
        title: Text(widget.title),
      ),
      //Center 可以将其子组件树对齐到屏幕中心,Center只能有一个孩子
      body: Center(
        //Column的作用是将其所有子组件沿屏幕垂直方向依次排列,Column可以有多个孩子,孩子用[]包裹起来
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      //这是一个浮动按钮
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        //描述按下按钮时将发生的操作的文本
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

_MyHomePageState类是MyHomePage类对应的状态类。我们发现MyHomePageMyApp 类不同, MyHomePage类中并没有build方法,取而代之的是,build方法被挪到了_MyHomePageState方法中,那么为什么要这样写呢?

原因

如果将build()方法放在StatefulWidget中则会有两个问题:

状态访问不便

如果我们的StatefulWidget有很多状态,而每次状态改变都要调用build方法,由于状态是保存在 State 中的,如果build方法在StatefulWidget中,那么build方法和状态分别在两个类中,那么构建时读取状态将会很不方便!试想一下,如果真的将build方法放在 StatefulWidget 中的话,由于构建用户界面过程需要依赖 State,所以build方法将必须加一个State参数,大概是下面这样:

Widget build(BuildContext context, State state){
        //state.counter
        ...
    }

这样的话就只能将 State 的所有状态声明为公开的状态,这样才能在 State 类外部访问状态!但是,将状态设置为公开后,状态将不再具有私密性,这就会导致对状态的修改将会变的不可控。但如果将build()方法放在 State 中的话,构建过程不仅可以直接访问状态,而且也无需公开私有状态,这会非常方便。

继承StatefulWidget不便

例如,Flutter 中有一个动画widget的基类AnimatedWidget,它继承自StatefulWidget类。AnimatedWidget中引入了一个抽象方法build(BuildContext context),继承自AnimatedWidget的动画widget都要实现这个build方法。现在设想一下,如果StatefulWidget 类中已经有了一个build方法,正如上面所述,此时build方法需要接收一个state对象,这就意味着AnimatedWidget必须将自己的 State 对象(记为_animatedWidgetState)提供给其子类,因为子类需要在其build方法中调用父类的build方法,代码可能如下:

class MyAnimationWidget extends AnimatedWidget{
      @override
      Widget build(BuildContext context, State state){
        //由于子类要用到AnimatedWidget的状态对象_animatedWidgetState,
        //所以AnimatedWidget必须通过某种方式将其状态对象_animatedWidgetState
        //暴露给其子类   
        super.build(context, _animatedWidgetState)
      }
  }

这样很显然是不合理的,因为

  1. AnimatedWidget的状态对象是AnimatedWidget内部实现细节,不应该暴露给外部。
  2. 如果要将父类状态暴露给子类,那么必须得有一种传递机制,而做这一套传递机制是无意义的,因为父子类之间状态的传递和子类本身逻辑是无关的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/900979.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10分钟使用Strapi(无头CMS)生成基于Node.js的API接口,告别繁琐开发,保姆级教程,持续更新中。

一、什么是Strapi&#xff1f; Strapi 是一个开源的无头&#xff08;headless&#xff09; CMS&#xff0c;开发者可以自由选择他们喜欢的开发工具和框架&#xff0c;内容编辑人员使用自有的应用程序来管理和分发他们的内容。得益于插件系统&#xff0c;Strapi 是一个灵活的 C…

【数据结构和算法】三、动态规划原理讲解与实战演练

目录 1、什么是动态规划&#xff1f; 2、动态规划实战演练 2.1 力扣题之爬楼梯问题 &#xff08;1&#xff09;解题思路1: &#xff08;2&#xff09;解题思路2: &#xff08;3&#xff09;动态规划&#xff08;DP&#xff09;&#xff1a;解题思路 &#xff08;4&#x…

【R + Python】iNaturalist 网站图片下载 inat api

文章目录 一、iNaturalist 简介二、R语言API&#xff1a;rinat三、示例3.1 获取观测数据3.2 绘制可视化图像函数用法 3.4 在区域网格中搜索3.5 下载图片3.51 提取图片 url3.52 下载图片: R语言3.53 下载图片: python 四、获取详细rinat包的文档 一、iNaturalist 简介 &#x1…

毕业设计选题:基于Python的招聘信息爬取和可视化平台

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 采集的数据列表 招聘数据大屏 摘要 本系统通过对网络爬虫的分析&#xff0c;研究智…

xlnt加载excel报错:xl/workbook.xml:2:2581: error: attribute ‘localSheetId‘ expected

解决方案 大家不一定能看懂&#xff0c;地址里说的啥意思&#xff0c;地址过去主要说明了从https://github.com/musshorn/xlnt/tree/issue_685合入可以解决问题&#xff0c;后面再想推送到官方地址&#xff0c;但没人维护了。 我这边直接给大家说一个结果就是&#xff1a;问题…

dbt-codegen: dbt自动生成模板代码

dbt项目采用工程化思维&#xff0c;数据模型分层实现&#xff0c;支持描述模型文档和测试&#xff0c;非常适合大型数据工程项目。但也需要用户编写大量yaml描述文件&#xff0c;这个过程非常容易出错且无聊。主要表现&#xff1a; 手工为dbt模型编写yaml文件&#xff0c;这过…

关于eclipse的workspace

如果项目很多&#xff0c;为了方便管理&#xff0c;最好不要是使用working set 对项目进行分组。一个workspace加载项目过多&#xff0c;即使进行分组&#xff0c;有些操作也很对所有项目生效。为了避免卡顿&#xff0c;建议直接使用workspace分组管理&#xff0c;而不是workin…

2024年妈杯MathorCup大数据竞赛A题超详细解题思路

2024年妈杯大数据竞赛初赛整体难度约为0.6个国赛。A题为台风中心路径相关问题&#xff0c;为评价预测问题&#xff1b;B题为库存和销量的预测优化问题。B题难度稍大于A题&#xff0c;可以根据自己队伍情况进行选择。26日早六点之前发布AB两题相关解题代码论文。 下面为大家带来…

Github优质项目推荐(第八期)

文章目录 Github优质项目推荐 - 第八期一、【manim】&#xff0c;66.5k stars - 创建数学动画的 Python 框架二、【siyuan】&#xff0c;19.5k stars - 个人知识管理软件三、 【GetQzonehistory】&#xff0c;1.3k stars - 获取QQ空间发布的历史说说四、【SecLists】&#xff0…

【C++篇】栈的层叠与队列的流动:在 STL 的韵律中探寻数据结构的优雅之舞

文章目录 C 栈与队列详解&#xff1a;基础与进阶应用前言第一章&#xff1a;栈的介绍与使用1.1 栈的介绍1.2 栈的使用1.2.1 最小栈1.2.2 示例与输出 1.3 栈的模拟实现 第二章&#xff1a;队列的介绍与使用2.1 队列的介绍2.2 队列的使用2.2.1 示例与输出 2.3 队列的模拟实现2.3.…

pair类型应用举例

在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <utility> //使能pair数据类型; #include <string> //使能string字符串; #include <stdlib.h> //使能exit(); //pair类型可以将两个相同的或不同类…

一个基于.NET8+WPF开源的简单的工作流系统

项目介绍 AIStudio.Wpf.AClient 是一个基于 WPF (Windows Presentation Foundation) 构建的客户端框架&#xff0c;专为开发企业级应用而设计。该项目目前版本为 6.0&#xff0c;进行了全面优化和升级&#xff0c;提供了丰富的功能和模块&#xff0c;以满足不同场景下的开发需…

张驰咨询:揭秘六西格玛项目如何“重塑”手术机器人集成度

项目背景 XR-1000型腔镜手术机器人是精智医疗公司最新推出的智能化手术设备&#xff0c;专注于微创外科手术&#xff0c;具有高度的精度和灵活性。随产品功能的扩展以及市场需求升级&#xff0c;系统集成度成为制约其性能提升的瓶颈。当前的设计中&#xff0c;机器人各模块的集…

C++20中头文件syncstream的使用

<syncstream>是C20中新增加的头文件&#xff0c;提供了对同步输出流的支持&#xff0c;即在多个线程中可安全地进行输出操作&#xff0c;此头文件是Input/Output库的一部分。包括&#xff1a; 1.std::basic_syncbuf&#xff1a;是std::basic_streambuf的包装器(wrapper)&…

Golang | Leetcode Golang题解之第509题斐波那契数

题目&#xff1a; 题解&#xff1a; type matrix [2][2]intfunc multiply(a, b matrix) (c matrix) {for i : 0; i < 2; i {for j : 0; j < 2; j {c[i][j] a[i][0]*b[0][j] a[i][1]*b[1][j]}}return }func pow(a matrix, n int) matrix {ret : matrix{{1, 0}, {0, 1}}…

格姗知识圈博客网站开源了!

格姗知识圈博客 一个基于 Spring Boot、Spring Security、Vue3、Element Plus 的前后端分离的博客网站&#xff01;本项目基本上是小格子一个人开发&#xff0c;由于工作和个人能力原因&#xff0c;部分技术都是边学习边开发&#xff0c;特别是前端&#xff08;工作中是后端开…

中电信翼康工程师:我在 Apache SeaTunnel 社区的贡献之旅

贡献者Github ID&#xff1a;luckyLJY 文章整理&#xff1a;曾辉 Apache SeaTunnel 作为一款强大的数据同步和转换工具&#xff0c;凭借其部署易用性、容错机制、数据源支持、性能优势、功能丰富性以及活跃的社区支持&#xff0c;成为了数据工程师们不可或缺的利器。 因其具有的…

LCD手机屏幕高精度贴合

LCD手机屏幕贴合&#xff0c;作为智能手机生产线上至关重要的一环&#xff0c;其质量直接关乎用户体验与产品竞争力。这一工艺不仅要求屏幕组件间的无缝对接&#xff0c;达到极致的视觉与触觉效果&#xff0c;还需确保在整个生产过程中&#xff0c;从材料准备到最终成品&#x…

Ansible 的脚本 --- playbooks剧本

playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Vars&#xff1a;变量 &#xff08;3&#xff09;Templates&#xff1a;模板 &a…

【JavaEE初阶】网络编程TCP协议实现回显服务器以及如何处理多个客户端的响应

前言 &#x1f31f;&#x1f31f;本期讲解关于TCP/UDP协议的原理理解~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不多说…