- xuanxuan2026-08-0417156
[!tip]-前言
本人近期在自学flutter,文章纯手敲,自己有Obsidian整理,内容太多先更新一部分,后续会继续更新。
接受各位佬批评,可自行修改错误或补充。
鼓励佬友共建,每次可赏10 ldc。
本文章如有问题,请联系我。Flutter UIFlutter widget 采用受React启发的现代框架构建。核心思想是用 widget 构建 UI。 Widget 根据当前配置和状态描述其视图应有的外观。当 widget 的状态改变时,widget 会重建其描述,框架将其与先前的描述进行 diff,以确定底层渲染树从一种状态过渡到另一种状态所需的最小变更。
[!info] Flutter官方文档
1. Flutter
1.1 Flutter 是什么
Flutter 是 Google 开发的开源 UI 框架,使用 Dart 语言编写。它的核心设计理念是一切皆 Widget。不同于其他跨平台框架依赖原生组件渲染,Flutter 自带高性能的渲染引擎 Skia(Impeller 在 iOS 上替代 Skia),直接在屏幕上绘制像素,从而实现真正的跨平台一致性。
Flutter 的目标平台覆盖极广:iOS、Android、Web、Windows、macOS、Linux。一套代码可以在六个平台上运行,这是它最吸引人的地方。
1.2 三层架构
层级 |
组成 |
职责 |Framework |
Dart 编写的 Widget 层、渲染层、动画层、手势层 |
开发者直接交互的 API 层 |Engine |
C/C++ 编写的 Skia/Impeller、Dart VM、文本渲染 |
负责渲染、线程管理、平台通信 |Embedder |
平台特定的代码(Java/Kotlin、Swift/Objective-C、C++) |
将 Engine 嵌入到各个操作系统中 |1.3 热重载与热重启
Flutter 的开发体验很大程度上归功于热重载(Hot Reload)。它借助 Dart 的 JIT 编译器,在代码修改后毫秒级地将变更注入到运行中的应用,同时保持应用状态。```
在终端中按 r 执行热重载(保留状态)
按 R 执行热重启(重新初始化状态)
按 q 退出
```> 热重载的局限
热重载不会重新执行
main()和initState()。如果你修改了全局变量初始化、枚举定义、类的静态字段,或者遇到编译错误,热重载会失败,需要使用热重启。1.4 项目结构```
my_app/
├── android/ # Android 原生工程
├── ios/ # iOS 原生工程
├── lib/ # Dart 代码(核心开发目录)
│ └── main.dart # 应用入口
├── test/ # 单元测试和 Widget 测试
├── pubspec.yaml # 依赖管理和资源配置
└── assets/ # 图片、字体等资源
``1.5pubspec.yaml详解``
name: demo
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0+1environment:
sdk: ^3.12.2dependencies:
flutter:
sdk: flutterdev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0flutter:
uses-material-design: true
```2. Widget 基础2.1 Widget 了解
在 Flutter 中,Widget 是构建 UI 的基本单位。按钮是 Widget,布局是 Widget,手势是 Widget,甚至是应用本身也是 Widget。Widget 描述的是 UI 的配置信息(即"长什么样"),而不是可变的 UI 实例。
Widget 的核心特点:
- 不可变(immutable):Widget 的字段都是
final的- 轻量级:Widget 本身不直接绘制,只是配置描述
- 可嵌套:通过组合多个 Widget 构建复杂 UI
2.1.1 启动```
void main() {
runApp(const MainApp());
}
```runApp()函数接收给定的Widget并将其设为 widget 树的根。2.1.2 Material 组件
Flutter 提供多种 widget,帮助你构建符合 Material Design 的应用。 Material 应用以
MaterialAppwidget 开头,它在应用根节点构建多种实用 widget,包括Navigator——管理以字符串标识的 widget 栈,即「路由」。```
class MainApp extends StatelessWidget {
const MainApp({super.key});@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
);
}
}
```MainApp是 根 widget,因为它是传入runApp的 widget。在这个 widget 内部,有一个build方法,它返回名为MaterialApp的另一个 widget。MaterialApp- title:用来展示窗口标题内容。
- theme:用来展示整个应用的主题。
- home:用来展示窗口的主题。```
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My First App',
theme: ThemeData(scaffoldBackgroundColor: Colors.deepPurple),
home: Scaffold(
body: Text("hello world"),
),
);
```2.1.2 Scaffold 组件Scaffold 提供标准、灵活配置的页面骨架。
属性 |
作用 |appBar |
页面顶部的应用栏,常用于显示标题、导航按钮和操作菜单 |body |
页面主题内容,可以放置任何其他组件 |bottomNavigationBar |
底部导航栏,方便用户在不同核心页面切换 |backgroundColor |
设置整个Scaffold 的背景色 |flotingActionButtom |
悬浮操作按钮,常用于触发页面主要动作 |… |
其他 |```
home: Scaffold(
appBar: AppBar(
title: Text('appbar'),
centerTitle: true,
),
body: Text("body"),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
},
child: Icon(Icons.add),
),
),
```2.1.3 两种核心 Widget 类型组件名称 |
类型 |
描述 |StatelessWidget |
无状态组件 |
StatelessWidget 一旦构建完成内部内容就不会再改变。它适用于纯展示型 UI,如文本、图标、静态图片等。 |StatefulWidget |
有状态组件 |
StatefulWidget 由两部分组成:Widget 本身(不可变)和 State(可变)。当状态变化时,调用setState()触发重建。 |(1)
StatelessWidget生命周期 |
|
|-
StatelessWidget非常简单:构造函数 →build()。没有额外的生命周期回调。- 当组件被创建或父组件状态变化导致需要重新构建时,
build()会被调用。```
class MainApp extends StatelessWidget {
const MainApp({super.key});@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
);
}
}
```> 总是使用 const 构造函数当
StatelessWidget的所有字段都是编译期常量时,使用const构造函数可以让 Flutter 在重建时复用同一个 Widget 实例,大幅提升性能。Flutter 官方推荐==尽可能使用 const==。(2)
StatefulWidget生命周期生命周期阶段 |
函数 |
描述 |
使用场景 |创建阶段 |
createState() |
widget初始化调用,创建state对象 |
|创建阶段 |
initState() |
state对象插入widget树立刻执行,仅执行一次 |
订阅流、初始化动画控制器、获取初始数据 |创建阶段 |
didChangeDependencies() |
initState()后立刻执行,当所依赖的InheritedsWidget更新时调用,可能多次 |
主题、本地化 |构建阶段 |
build() |
构建UI,初始化或更新后多次调用 |
|更新阶段 |
didUpdateWidget() |
父组件传入新配置时调用,用于比较新旧配置 |
父 Widget 重建时,传入新配置 |销毁阶段 |
deactivate() |
当state对象从widget树暂时移除时调用 |
|销毁阶段 |
dispose() |
当state对象从widget树永久移除时调用,释放资源,仅执行一次 |
取消订阅、释放动画控制器、关闭资源 |```
// 第一个类继承StatefulWidget,主要接受和定义最终参数,核心作用创建State对象
class Counter extends StatefulWidget {
const Counter({super.key});@override
State<Counter> createState() => _CounterState();
}// 第二个类继承State<第一个类类名>,负责管理可变数据和业务逻辑,并实现build方法来渲染视图。
class _CounterState extends State<Counter> {
int _count = 0;void _increment() {
setState(() {
_count++;
});
}@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _increment,
child: Text('Count: $_count'),
);
}
}
``生命周期函数``
补充
```2.2 布局组件Flutter 布局的核心机制是 widget。在 Flutter 中,几乎所有东西都是 widget — 甚至布局模型都是 widget。
所有布局 widget 都具有以下任一项:
- 一个
child属性,如果它们只包含一个子项 — 例如Center和Container- 一个
children属性,如果它们包含多个子项 — 例如Row、Column、ListView和Stack2.2.1 布局组件
Container
- 组合容器,整合尺寸(
width/height)、装饰(decoration/color)、边距(padding/margin)、对齐(alignment)、变换(transform);-
decoration属性:装饰器,可实现复杂背景效果,不能与color同时使用;- 与
SizeBox区别:SizeBox只能设置尺寸,无其他属性。特性:
- 不设宽高时,会尽可能占满父空间;
-
padding内部留白,margin外部留白;- 有
child才会渲染内部内容。```
body: Center(
child: Container(
width: 200, // 宽
height: 100, // 高
padding: EdgeInsets.all(10), // 内边距
margin: EdgeInsets.symmetric(vertical: 20), // 外边距
decoration: BoxDecoration(
// 背景装饰
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 4)],
),
alignment: Alignment.center, // 内部子控件对齐
transform: Matrix4.rotationZ(0.1), // 旋转/平移
child: Text("Container"),
),
),- 将子组件在父容器空间内水平居中和垂直居中; - `Center = Align(alignment: Alignment.center)`,简化版居中; - 不能设置宽高,会尽可能占满父空间;``` body: Center( child: Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 4)], ), alignment: Alignment.center, child: Text("center"), ), ),- 精确控制子控件在父容器内的位置,可设置宽高因子。```
body: Container(
width: 300,
height: 200,
color: Colors.grey,
child: Align(
alignment: Alignment.bottomRight, // 右下角
widthFactor: 0.5, // 自身宽度=父宽度*0.5
heightFactor: 0.5, // 自身高度=父高度*0.5
child: Text("右下角文字"),
),
),- 控制子控件的内边距``` body: Container( color: Colors.amber, child: Padding( padding: EdgeInsets.all(20), child: Container( color: Colors.blue, ), ), ), ```Column & Row **Column** - 线性布局,垂直排列子控件 属性 | 描述 | `mainAxisAlignment` | 控制子控件在主轴(垂直方向)的排列方式,顶部对齐、居中。均匀分布 | `crossAxisAlignment` | 控制子控件在交叉轴(水平方向)的排列方式,左/右对齐、拉伸填满 | `mainAxisSize` | 决定Column在垂直方向上的尺寸策略。沾满所有空间(max),仅仅包裹子控件内容(min) | `children` | 垂直排列子控件列表 |``` body: Container( width: double.infinity, height: double.infinity, color: Colors.amber, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Container( color: Colors.blue, width: 200, height: 200, alignment: Alignment.center, child: Text('111'), ), Container( width: 200, height: 200, alignment: Alignment.center, color: Colors.green, child: Text('222'), ), ], ), ), ```**Row** - 线性布局,水平排列子控件 属性 | 描述 | `mainAxisAlignment` | 控制子控件在主轴(水平方向)的排列方式,顶部对齐、居中。均匀分布 | `crossAxisAlignment` | 控制子控件在交叉轴(垂直方向)的排列方式,左/右对齐、拉伸填满 | `mainAxisSize` | 决定Row在水平方向上的尺寸策略。沾满所有空间(max),仅仅包裹子控件内容(min) | `children` | 垂直排列子控件列表 |``` body: Container( width: double.infinity, height: double.infinity, color: Colors.amber, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Container( color: Colors.blue, width: 200, height: 200, alignment: Alignment.center, child: Text('111'), ), Container( width: 200, height: 200, alignment: Alignment.center, color: Colors.green, child: Text('222'), ), ], ), ), ```Flex & Expended **Flex** - 弹性布局,允许沿着一个主轴(水平或垂直)排列子控件,灵活控制子控件在主轴上的尺寸比例和空间分配。相当于是`Row和Column`结合 属性 | 描述 | `direction` | 主轴方向`Axis.horizontal`水平,`Axis.vertical垂直 | `mainAxisAlignment` | 控制子控件在主轴(水平/垂直方向)的排列方式 | `crossAxisAlignment` | 控制子控件在交叉轴(垂直/水平方向)的排列方式 | `mainAxisSize` | 决定Row在水平方向上的尺寸策略。沾满所有空间(max),仅仅包裹子控件内容(min) | `children` | 垂直排列子控件列表 | **Expended** | | - Expended/Flexible 作为`Flex`的子控件通过`flex`属性来分配`Flex组件`的空间。 属性 | 描述 | `flex` | 分配子控件在`Flex组件`的空间 | `child` | 子控件 |``` body: Container( width: double.infinity, height: double.infinity, color: Colors.amber, child: Flex( direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Expanded( flex: 2, child: Container( alignment: Alignment.center, color: Colors.red, width: 200, height: 200, child: Text('111'), ), ), Expanded( flex: 1, child: Container( alignment: Alignment.center, color: Colors.green, width: 200, height: 200, child: Text('222'), ), ), ], ), ),- 流式布局,当子控件在主轴上排列不下时,它会自动换行(或换列)。
- flex/row/column的内容超出不会自动换行
属性 |
描述 |direction|
主轴方向Axis.horizontal水平,`Axis.vertical垂直 |spacing|
控制子控件在主轴的间距 |runSpacing|
控制子控件在交叉轴的间距 |alignment|
控制子控件在主轴的对齐方式 |runAlignment|
控制子控件在交叉轴的对齐方式 |```
body: Container(
width: double.infinity,
height: double.infinity,
color: Colors.amber,
child: Wrap(
direction: Axis.horizontal,
spacing: 20,
runSpacing: 20,
alignment: WrapAlignment.spaceBetween,
runAlignment: WrapAlignment.center,
children: [
Container(
alignment: Alignment.center,
color: Colors.red,
width: 200,
height: 200,
child: Text('111'),
),
Container(
alignment: Alignment.center,
width: 200,
height: 200,
color: Colors.green,
child: Text('222'),
),
],
),
),
```Stack & PositionedStack
- 层叠布局,允许将多个子控件按Z轴方向进行叠加排序。
属性 |
描述 |alignment|
控制非定位的子控件在Stack内的对齐方式,默认左上角 |fit|
控制非定位的子控件如何适应Stack的尺寸 |clipBehavor|
控制非定位的子控件在Stack超出部分的裁剪方式 |children|
需要叠层子控件列表 |Positioned |
|- 层叠布局,必须作为
Stack的子控件,属性 |
描述 |top/bottom/left/right|
控制子控件在Stack的位置 |child|
子控件 |```
body: Container(
width: double.infinity,
height: double.infinity,
color: Colors.amber,
child: Stack(
alignment: Alignment.center,
children: [
Container(
alignment: Alignment.center,
color: Colors.red,
width: 200,
height: 200,
),
Positioned(
top: 10,
left: 10,
child: Container(
height: 100,
width: 100,
color: Colors.green
),
),
Positioned(
bottom: 10,
right: 10,
child: Container(
height: 100,
width: 100,
color: Colors.blue
),
),
],
),
),
```2.2.2 滚动 & 列表 & 网格widget |
特征 |
使用场景 |SingleChildScrollView|
让单个子控件可以用滚动,所有内容一次性渲染 |
长表单,设置页、内容不固定但是总量不多的页面 |ListView|
线性列表,通过builder可实现懒加载,性能优异 |
聊天记录、新闻、常见单列滚动数据列表 |GridView|
网格列表,支持懒加载,可固定列数 |
图片墙、商品网格、应用图标列表 |CustomScrollView|
复杂布局方案,通过组合多个Sliver组件实现滚动 |
电商首页、社交app个人主页多个滚动紧密联动 |PageView|
整页滚动,支持横向和纵向滚动 |
应用引导页、图片轮播、书籍翻页 |SingleChildScrollView- 让单个子控件可以用滚动,所有内容一次性渲染
属性 |
描述 |controller|
控制滚动,绑定一个ScrollController对象给controller对象,通过animateTo/jumpTo方法实现控制滚动 |scrollDirection|
滚动方向,Axis.horizontal水平滚动,Axis.vertical垂直滚动 |```
class _TestAppState extends State<TestApp> {
ScrollController _scrollController = ScrollController();@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Stack(
children: [
SingleChildScrollView(
controller: _scrollController,
child: Column(
children: List.generate(
10,
(index) => Container(
height: 200,
width: double.infinity,
margin: EdgeInsets.all(10),
color: Colors.red,
alignment: Alignment.center,
child: Text('$index'),
),
),
),
),Positioned(
top: 10,
right: 10,
child: GestureDetector(
onTap: () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Container(
height: 100,
width: 100,
alignment: Alignment.center,
color: Colors.blue,
child: Text('去底部'),
),
),
),Positioned(
bottom: 10,
right: 10,
child: GestureDetector(
onTap: () {
_scrollController.animateTo(
0,
duration: const Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Container(
height: 100,
width: 100,
alignment: Alignment.center,
color: Colors.blue,
child: Text('去顶部'),
),
),
),
],
),
),
);
}
}
```ListView- 线性列表,通过builder可实现懒加载,性能优异
- 提供多种构造函数,如默认构造函数、
ListView.builder、ListView.separated- 采用按需渲染懒加载,只构建当前可见区域的列表项,极大提高长列表性能
属性 |
描述 |controller|
控制滚动,绑定一个ScrollController对象给controller对象,通过animateTo/jumpTo方法实现控制滚动 |scrollDirection|
滚动方向,Axis.horizontal水平滚动,Axis.vertical垂直滚动 |itemCount|itemCount控制列表长度 |itemBuilder|itemBuilder回调函数按需构建列表项 |separatorbuilder|
需在ListView.separated使用,为列表提供分割线 |```
// ListView.builder
class _TestAppState extends State<TestApp> {
final ScrollController _scrollController = ScrollController();@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Stack(
children: [
ListView.builder(
controller: _scrollController,
itemCount: 10,
itemBuilder: (context, index) => Container(
height: 200,
width: double.infinity,
margin: EdgeInsets.all(10),
color: Colors.red,
alignment: Alignment.center,
child: Text('$index'),
),
),
],
),
),
);
}
}// ListView.separated
class _TestAppState extends State<TestApp> {
final ScrollController _scrollController = ScrollController();@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Stack(
children: [
ListView.separated(
controller: _scrollController,
itemCount: 10,
separatorBuilder: (context, index) => Container(
height: 10,
width: double.infinity,
color: Colors.grey,
),
itemBuilder: (context, index) => Container(
height: 200,
width: double.infinity,
color: Colors.red,
margin: EdgeInsets.all(10),
alignment: Alignment.center,
child: Text('$index'),
),
),
],
),
),
);
}
}
```GridView- 二维网格列表,支持懒加载,可固定列数
- 提供多种构造函数,
GridView.count(固定列数的网格布局)、GridView.extent(固定子项最大宽度/高度的网格布局)、GridView.builder(网格数量巨大或动态生成、需接收girdDelegate布局委托属性),默认构造函数使用起来复杂,很少用。属性 |
描述 |scrollDirection|
滚动方向,Axis.horizontal水平滚动,Axis.vertical垂直滚动 |controller|
控制滚动,绑定一个ScrollController对象给controller对象,通过animateTo/jumpTo方法实现控制滚动 |mainAxisSpacing|
主轴间距 |crossAxisSpacing|
交叉轴间距 |crossAxisCount|
需在GridView.count下使用,固定列数 |maxCrossAxisExtent|
需在GridView.extent中使用,固定子项最大宽度/高度 |girdDelegate|crossAxisCount固定列数、mainAxisSpacing主轴间距、crossAxisSpacing交叉轴间距 |```
// GridView.count
body: GridView.count(
crossAxisCount: 4,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
children: List.generate(
20,
(index) => Container(
color: Colors.green,
alignment: Alignment.center,
child: Text('$index'),
),
),
),// GridView.extent
body: GridView.extent(
scrollDirection: Axis.horizontal,
maxCrossAxisExtent: 200,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
children: List.generate(
20,
(index) => Container(
color: Colors.green,
alignment: Alignment.center,
child: Text('$index'),
),
),
),// GridView.builder
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: 100,
itemBuilder: (context, index) {
return Container(
color: Colors.green,
alignment: Alignment.center,
child: Text('$index'),
);
},
),
```CustomScrollView- 复杂布局方案,组合多个滚动组件(列表、网格),通过组合多个
Sliver组件实现滚动-
sliver是描述可滚动视图内的一部分内容的子控件,它是滚动视图的切片。属性 |
描述 |controller|
控制滚动,绑定一个ScrollController对象给controller对象,通过animateTo/jumpTo方法实现控制滚动 |scrollDirection|
滚动方向,Axis.horizontal水平滚动,Axis.vertical垂直滚动 |slivers|
用于接受Sliver组件列表。 |slivers组件对应关系子控件名称 |
对应组件 |
作用 |SliverAppBar|AppBar|
可折叠、悬浮、固定头部,嵌套在CustomScrollView|SliverPadding|Padding|
给 Sliver 子组件增加内边距(不能直接包裹普通 Widget) |SliverToBoxAdapter|
无直接对等组件 |
将普通RenderBoxWidget(Container/Text 等)转为 Sliver,混合布局必备 |SlievrPersistentHeader|
无直接对等组件 |
持久吸顶头部,滚动时可以固定在顶部(自定义伸缩头部核心) |SliverList|ListView|
列表懒加载,对应ListView.builder逻辑 |SliverGird|GridView|
网格布局,对应GridView.builder|```
class _TestAppState extends State<TestApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(title: Text("123"), pinned: true),
SliverToBoxAdapter(
child: Container(height: 200.0, color: Colors.red),
),
SliverList.builder(
itemCount: 10,
itemBuilder: (context, index) => Container(
height: 100,
width: double.infinity,
color:Colors.blue,
margin: EdgeInsets.all(10),
child: Text("第"'$index'"个"),
),
),
],
),
),
);
}
}
```PageView- 整页滚动,支持横向和纵向滚动,实现分页滚动视图。
- 提供多种构造函数,默认构造函数、
PageView.bulider(懒加载)属性 |
描述 |controller|
控制滚动,绑定一个ScrollController对象给controller对象,通过animateTo/jumpTo方法实现控制滚动 |scrollDirection|
滚动方向,Axis.horizontal水平滚动,Axis.vertical垂直滚动 |```
class _TestAppState extends State<TestApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
height: 200,
color: Colors.blue,
child: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (BuildContext context, int index) => Container(
margin: EdgeInsets.all(10.0),
color: Colors.red,
alignment: Alignment.center,
child: Text('第${(index+1)}页'),
),
),
),
),
);
}
}> [!danger] ^-^启动主楼 - qdd282026-08-0415254
万物皆widget,套又又套去,大概就是这个意思。