当前位置: 首页 > news >正文

第4讲:理解Flutter的灵魂 - “Everything is a Widget”

掌握Widget,你就掌握了构建FlutterUI世界的基本法则。

你好,欢迎回到《Flutter入门到精通》专栏。在上一讲中,我们剖析了Flutter项目的结构,并体验了热重载的神奇。你可能已经注意到,代码中充满了各种各样的 Widget。没错,在Flutter的世界里,一切皆是Widget

本讲将带你深入理解Widget的概念,区分无状态与有状态Widget,并亲手构建你的第一个自定义Widget。

一、什么是Widget?UI的构建块

1.1 Widget的本质

简单来说,Widget是您用于声明和构建用户界面的蓝图或配置

它并不代表最终绘制在屏幕上的UI元素,而是一个描述。Flutter框架会根据这些Widget的配置信息,创建出相应的、高效的渲染对象,最终由Skia引擎绘制到屏幕上。

一个生动的比喻:

  • Widget 就像建筑图纸。它描述了房子的结构、房间的布局、门窗的样式。

  • Flutter框架 就像施工队,它读取图纸(Widget),调用建筑材料(渲染对象),最终建起真正的房子(用户界面)。

  • 当你想改变一扇窗(UI)时,你不需要自己去拆墙,你只需要修改图纸(更新Widget),施工队(Flutter框架)就会高效地帮你完成更新。

1.2 Widget树:UI的层次结构

Flutter的UI是通过嵌套Widget来构建的,形成一个Widget树

让我们回顾一下上一讲计数器应用中的 build 方法:

dart

@override
Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(widget.title), // AppBar 包含一个 Text),body: Center( // Center 包含一个 Columnchild: Column( // Column 包含两个 Textchildren: <Widget>[const Text('You have pushed the button this many times:'),Text('$_counter'),],),),floatingActionButton: FloatingActionButton( // 一个独立的WidgetonPressed: _incrementCounter,child: const Icon(Icons.add), // FloatingActionButton 包含一个 Icon),);
}

这段代码对应的Widget树可以简化为:

text

Scaffold
├── AppBar
│   └── Text
├── Center
│   └── Column
│       ├── Text
│       └── Text
└── FloatingActionButton└── Icon

理解Widget树是理解Flutter布局和渲染的关键。


二、StatelessWidget vs StatefulWidget:核心区别

这是Flutter中最重要的概念之一。所有Widget都基于这两种类型之一。

2.1 StatelessWidget(无状态Widget)

  • 定义: 一旦创建,其内部状态就不可变的Widget。它就像一张静态图片。

  • 特点

    • 它依赖于父Widget传递过来的初始配置信息和自身不变的固有属性。

    • 它不存储任何会随时间变化的数据。

    • 它只有一个必需的 build 方法。

  • 常见例子: TextIconImageAppBar 等。

创建一个简单的StatelessWidget:

让我们创建一个显示问候语的Widget。

dart

// 定义一个名为 GreetingText 的无状态Widget
class GreetingText extends StatelessWidget {// 构造函数:接收一个不可变的最终属性 `name`const GreetingText({super.key, required this.name});// 声明一个 final 成员变量,意味着它一旦被赋值就不能再改变final String name;// 必须实现的 build 方法,描述如何构建这个Widget@overrideWidget build(BuildContext context) {return Text('Hello, $name!', // 使用传入的 name 属性style: const TextStyle(fontSize: 20),);}
}

如何使用它?
在你之前 MyHomePage 的 body 中,可以这样使用:

dart

body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[GreetingText(name: 'Flutter Developer'), // 在这里使用!Text('$_counter'),],),
),

2.2 StatefulWidget(有状态Widget)

  • 定义: 在其生命周期内,持有可变状态的Widget。它就像一个可以播放的视频播放器,其播放进度、音量等状态会变化。

  • 特点

    • 它由两个类组成:一个不可变的 StatefulWidget 子类和一个可变的 State 子类。

    • 状态(数据)存储在 State 对象中,而不是 StatefulWidget 本身。

    • 当状态改变时,调用 setState() 来通知框架重建UI。

  • 常见例子: 带有表单输入的页面、动画、计数器(我们之前的 MyHomePage 就是)。

剖析StatefulWidget的结构:

计数器应用中的 MyHomePage 就是一个完美的例子。我们来分解它:

dart

// 1. StatefulWidget 部分:本身是不可变的,主要负责接收和传递初始配置
class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title; // 不可变的属性// 这个方法创建并返回管理状态的 State 对象@overrideState<MyHomePage> createState() => _MyHomePageState();
}// 2. State 部分:这里是状态和逻辑存在的地方
class _MyHomePageState extends State<MyHomePage> {int _counter = 0; // 可变的状态!存储在这里void _incrementCounter() {// 修改状态,并通知框架“状态已改变,请重建UI!”setState(() {_counter++;});}@overrideWidget build(BuildContext context) {// build 方法在 State 类中!// 它可以访问可变状态 (_counter) 和来自Widget的不可变属性 (widget.title)return Scaffold(appBar: AppBar(title: Text(widget.title)), // 使用 widget.[属性名] 访问body: Center(child: Text('$_counter')), // 使用状态 _counterfloatingActionButton: FloatingActionButton(onPressed: _incrementCounter),);}
}

关键点总结:

特性StatelessWidgetStatefulWidget
状态不可变可变(存储在单独的 State 对象中)
组成一个类两个类:StatefulWidget + State
性能较轻量相对较重(因为需要管理状态生命周期)
使用场景静态内容、展示型UI交互式UI、动态数据、动画

三、实践:构建一个交互式自定义Widget

现在,让我们综合所学,创建一个全新的、包含交互的自定义StatefulWidget——一个简单的“喜欢”按钮。

  1. 在 lib 文件夹下,新建一个Dart文件,比如 like_button.dart

  2. 在文件中写入以下代码:

dart

import 'package:flutter/material.dart';class LikeButton extends StatefulWidget {// 构造函数:可以接收一个初始的喜欢状态,默认为falseconst LikeButton({super.key, this.isLiked = false});final bool isLiked;@overrideState<LikeButton> createState() => _LikeButtonState();
}class _LikeButtonState extends State<LikeButton> {// 状态:这个按钮当前是否被“喜欢”bool _isLiked = false;// 初始化状态:我们可以用从Widget传过来的初始值来设置状态@overridevoid initState() {super.initState();_isLiked = widget.isLiked;}// 处理点击事件的方法void _toggleLike() {setState(() {_isLiked = !_isLiked; // 切换喜欢状态});}@overrideWidget build(BuildContext context) {return GestureDetector( // 一个可以检测手势的WidgetonTap: _toggleLike, // 当被点击时,调用 _toggleLike 方法child: Row(mainAxisSize: MainAxisSize.min, // 让Row只占用所需的空间children: [Icon(_isLiked ? Icons.favorite : Icons.favorite_border, // 根据状态选择图标color: _isLiked ? Colors.red : Colors.grey, // 根据状态选择颜色),const SizedBox(width: 5), // 添加一些间距Text(_isLiked ? 'Liked' : 'Like'), // 根据状态显示文本],),);}
}
  1. 在 main.dart 中引入这个文件,并在 MyHomePage 的 body 中使用它:

dart

// 在文件顶部导入
import 'like_button.dart';// ... 在 MyHomePage 的 body 的 Column 的 children 中添加 ...
body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('Check out this new feature:'),LikeButton(), // 使用默认值const SizedBox(height: 20), // 添加垂直间距LikeButton(isLiked: true), // 使用初始值为trueconst SizedBox(height: 20),Text('Counter: $_counter'),],),
),

现在运行你的应用,你应该能看到两个“Like”按钮,点击它们可以独立地在“Like”和“Liked”状态之间切换!

结语

恭喜!你已经迈出了成为Flutter开发者的最关键一步。你不仅理解了Widget是Flutter UI的基石,还掌握了无状态与有状态Widget的核心区别与创建方法,并成功构建了属于自己的交互式组件。

记住这个简单的决策流程:如果你的UI部分需要根据数据变化而改变,就使用StatefulWidget;如果它只是静态展示,就使用StatelessWidget。

在下一讲中,我们将暂时放下抽象概念,开始学习具体的、强大的布局与基础Widget,如 ContainerRowColumnStack 等,让你能够构建出更加复杂和精美的界面。

http://www.dtcms.com/a/553089.html

相关文章:

  • 驱动精灵、驱动人生、NVIDIA专业显卡驱动、360驱动大师、联想乐驱动,电脑驱动修复工具大全
  • Spring Boot 4与Spring Framework 7:云原生Java的全新革命与企业级实战
  • 虚拟机在云原生与智能时代的未来应用场景探析
  • 电脑如何设置wifi密码,详细步骤教程指南
  • C#面试题及详细答案120道(51-60)-- LINQ与Lambda
  • 北京网站备案的地址ps怎么做网站分隔线
  • DLSS是什么
  • web网页开发,旧版在线%考试,判题%系统demo,基于python+flask+随机分配考试题目,基于开发语言python,数据库mysql
  • 【C++】哈希表封装实现 unordered_map 和 unordered_set
  • 353-Spring AI Alibaba ARK 多模型示例
  • 安徽海绵城市建设协会网站ip查询网站备案查询系统
  • MVVM架构与ICommand核心笔记
  • Web后端开发学习总结
  • 萍乡做网站的公司有哪些门户网站建设方案ppt 百度文库
  • Wireshark抓包教程:获取网站登录凭证
  • 销售驱动的黄昏:医药商业化模式的效率悖论与转型必然
  • 【mysql】锁机制 - 2.行锁间隙锁临键锁
  • 做网站制作需要多少钱网络设计公司有哪些
  • 外卖骑手的Python转型指南:从送餐到编程的实战路径
  • 一款端侧TTS:NeuTTS-Air,3秒语音克隆,声音听起来没有生硬感,语气和节奏感相对自然
  • 网站建设网站软件页面设计属于什么知识产权
  • 网站管理的含义长春做网站哪家好
  • Nacos和Nginx集群,项目启动失败问题
  • Opencv(五): 腐蚀和膨胀
  • 17.React获取DOM的方式
  • 编码器读写操作方式
  • WEB服务
  • 2025年10月31日 AI大事件
  • Rust开发中泛型结构体定义与使用(通用容器)
  • 9-SpringCloud-服务网关 Gateway-高级特性之 Filter-2