Flutter 常用 Widget 分类速查表
按图中脉络,将核心组件分为 6 大类,并补充每类典型用途与要点。
| 分类 | 常见 Widget | 典型作用 / 备注 |
|---|---|---|
| 布局 Widget (Layout) | 单子元素布局 Container、Center、Align、FractionallySizedBox、SizedBox、FittedBox、ConstrainedBox、OverflowBox、AspectRatio、Offstage |
控制 单个子组件 的尺寸、位置或可见性。 Container = 装饰 + 约束 + 边距的一站式方案;Offstage 用于临时隐藏但保留状态。 |
多子元素布局 Row、Column、Stack、IndexedStack、Flow、Table、Wrap、ListBody |
负责 多个子组件 排版。 Row/Column 线性排列;Stack 层叠定位;Wrap/Flow 流式换行;Table 网格;IndexedStack 仅显示指定索引子项。 |
|
| 可滚动 Widget | ListView, GridView, NestedScrollView, CustomScrollView |
内建滚动能力。NestedScrollView 适合协同滚动 AppBar;CustomScrollView 能组合多个 Sliver 实现复杂滚动效果。 |
| 绘制 & 效果 Widget | Opacity, Transform, DecoratedBox, FractionalTranslation, RotatedBox, ClipOval, ClipPath, ClipRect, CustomPaint, BackdropFilter |
图形变换、裁剪、透明度、装饰与自绘。CustomPaint 可绘制任意图形;BackdropFilter 做毛玻璃等高斯模糊。 |
| 图片与资源 Widget | Image, Icon, RawImage, (资源加载辅助:AssetBundle) |
加载位图或矢量资源。RawImage 直接显示 ui.Image;AssetBundle 为多平台统一的资源检索接口。 |
| 文本 Widget | Text, RichText |
渲染普通文本或富文本;RichText 支持多样式 TextSpan 嵌套。 |
| 样式 Widget | Padding, Theme, MediaQuery |
提供边距、全局主题与环境信息(屏幕尺寸、文字缩放、暗色模式)。 |
- 尺寸与约束不满足时,优先考虑
SizedBox/ConstrainedBox。 - 复杂滚动场景优先研究 Sliver 系列 与
CustomScrollView。 - 动态裁剪或特效可组合
ClipPath+BackdropFilter。 - 跨页面共享配色/字体,统一写在
ThemeData,并用Theme.of(context)读取。
StatelessWidget与StatefulWidget
StatelessWidget 与 StatefulWidget 全面对比
| 维度 | StatelessWidget | StatefulWidget |
|---|---|---|
| 核心定义 | 无可变状态 。构建后只能依赖 build() 里传入的 外部参数 (构造函数、InheritedWidget、Provider 等)来决定外观。 |
拥有可变状态 。通过内部 State 对象保存数据,调用 setState() 后可触发重新构建自身及其子树。 |
| 典型场景 | - 纯展示组件 - Button、Icon、Logo 等简单静态 UI - 只依赖父级传值、不需自行更新 | - 表单输入、计时器、动画、Tab 切换 - 网络请求完成后刷新页面 - 需要局部记忆 / 交互的组件 |
| 生命周期 | ```dart | |
| Widget build(BuildContext context) | ||
``` 只有一次 build,依赖更新 ⇒ 整棵 Widget 重新创建。 |
常用回调: initState()→didChangeDependencies()→build()→setState()→dispose() |
|
| 更新机制 | 父级的 setState() 或 InheritedWidget 改变后,Flutter 框架会销毁旧实例,创建新实例执行 build()。 |
调用自身 setState(fn) ⇒ 仅当前 StatefulWidget 重新 build(),子树中未变化的内容利用 Element 树 Diff 被高效复用。 |
| 性能 | 占用内存少、构建开销低;如果 UI 真正静态,更利于框架优化。 | 略高,但局部刷新的粒度更细,避免整页重绘。正确拆分可获得更佳整体性能。 |
| 转换 | 业务增长需本地状态 → 可 快捷替换 : 1. 用 IDE 将类继承改为 StatefulWidget 2. 自动生成 State,再挪动原 build() |
状态已不再需要 ⇒ 把业务状态上提或放入 Provider/Riverpod/BLoC,然后改为 StatelessWidget,使组件更轻量。 |
| 易错点 | - 不支持 setState();如直接调用会报错。 |
- 忘记 dispose() 释放资源(AnimationController、Stream、Timer)。 - 在 build() 里创建 Future/Stream 导致反复执行;应缓存。 |
1. 快速示例对比
StatelessWidget
dart
class HelloText extends StatelessWidget {
final String name;
const HelloText({required this.name, super.key});
@override
Widget build(BuildContext context) {
return Text('Hello, $name');
}
}
StatefulWidget
dart
class CounterBtn extends StatefulWidget {
const CounterBtn({super.key});
@override
State<CounterBtn> createState() => _CounterBtnState();
}
class _CounterBtnState extends State<CounterBtn> {
int _count = 0;
void _inc() => setState(() => _count++);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _inc,
child: Text('Clicked $_count'),
);
}
}
2. 何时选谁?
-
完全静态或仅依赖外部数据 → Stateless。
-
需在组件内用
setState()更新 → Stateful。 -
状态要跨组件 / 全局共享 → 把状态上提或使用状态管理,再让 UI 尽量保持 Stateless。
3. 状态拆分的小技巧
- 最小重绘原则 :
把仅因点击计数变化的部分包成StatefulWidget,周围稳定区域仍用StatelessWidget,减少重建。 AutomaticKeepAliveClientMixin:
滑动页签PageView/TabBarView中要保持页面状态,可在State里混入并重写wantKeepAlive => true;。- Keys :
当控件类型相同但需要唯一身份(动画切换、列表重排)时,使用ValueKey/ObjectKey/UniqueKey保持状态不丢失。
4. 小结
- StatelessWidget:纯展示、所有数据都从外部流入。
- StatefulWidget :自己的状态自己管,
setState()后局部刷新。 - 合理拆分与状态上提可以兼顾 可维护性 与 性能。
- 如果组件既要管理内部细节,又要暴露事件给外部,推荐"内部 Stateful + 对外 Stateless API"的封装方式,提高复用度。
Android开发者如何快速上手Flutter布局开发
1. LinearLayout 在 Flutter 中等价于什么?
| Android | Flutter | 说明 |
|---|---|---|
LinearLayout (horizontal / vertical) |
Row (横向) Column(纵向) |
Row / Column 只负责子组件线性排列 ,额外尺寸/权重需要 Expanded、Flexible、Spacer 等配合。 |
dart
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('A'),
Text('B'),
],
)
2. RelativeLayout 在 Flutter 中等价于什么?
| Android | Flutter | 用途 |
|---|---|---|
RelativeLayout |
Stack + Positioned / Align |
Stack 允许子组件"层叠"摆放;通过 Positioned(绝对偏移)或 Align(相对父尺寸)来模拟 RelativeLayout 效果。 |
dart
Stack(
children: [
Container(color: Colors.blue), // 底层
Positioned(top: 8, right: 8, child: Icon(Icons.close)),
],
)
3. 如何使用 Widget 定义布局属性?
在 Flutter 中,"布局 + 样式"都是由 一层层 Widget 组合实现,而非 XML。常见属性对应的 Widget/参数:
| 功能 | Widget / 参数示例 |
|---|---|
| 边距、内边距 | Padding(padding: EdgeInsets.all(8)) |
| 大小约束 | SizedBox(width: 100, height: 50) / ConstrainedBox |
| 对齐 | Align(alignment: Alignment.centerRight) |
| 权重(填充剩余) | Expanded(child: ...)、Flexible(flex: 2, child: ...) |
| 背景装饰 | Container(decoration: BoxDecoration(color: Colors.red)) |
4. 如何分层布局?
- 透明层叠 :
Stack - 滚动内部再分层 :
CustomScrollView+ 各种Sliver - 浮动/悬浮元素 :
Stack+Positioned放在屏幕顶层,或使用Scaffold的floatingActionButton、Drawer、BottomSheet等 slot。
5. 如何设置布局样式?
- 颜色 / 圆角 / 阴影 →
Container → BoxDecoration - 字体 / 主题 →
ThemeData+TextStyle - 动画样式 →
AnimatedContainer,AnimatedPositioned,Hero - 适配暗黑模式 → 读取
Theme.of(context).brightness或MediaQuery.platformBrightnessOf(context)
dart
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(blurRadius: 4, color: Colors.black26)],
),
child: const Text('样式示例'),
)
6. ScrollView 在 Flutter 中等价于什么?
| Android | Flutter | 备注 |
|---|---|---|
ScrollView / NestedScrollView |
SingleChildScrollView (单子组件) CustomScrollView(多 Sliver 组合滚动) |
若仅需包一段静态内容,用 SingleChildScrollView;复杂协同滚动(如 AppBar 吸顶)用 NestedScrollView 或 CustomScrollView + Slivers。 |
7. 谁是 Flutter 的列表组件?
-
ListView:最常用ListView(children: [...])静态少量ListView.builder(itemCount: n, itemBuilder: ...)懒加载ListView.separated(...)带分割线
-
GridView:网格 -
ListView.custom/SliverList:高度自定义 -
ReorderableListView:可拖拽排序 -
AnimatedList:插入/删除动画
8. 如何知道点击了列表中哪个 item?
dart
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
onTap: () {
print('点击了第 $index 个:${items[index]}');
},
);
},
)
- 可替换
ListTile为GestureDetector,InkWell等,自由处理onTap。
9. 如何动态更新 ListView?
-
StatefulWidget + setState
dartsetState(() { items.add('新元素'); }); -
更平滑的插入/删除动画 → 用
AnimatedList -
大规模异步数据 → 结合
StreamBuilder/FutureBuilder或状态管理(Provider、Riverpod、Bloc 等) -
局部刷新 → 使用
ValueNotifier<List<T>>+ValueListenableBuilder或者ListView.builder本身的懒加载特性。
🌟 小结
- 线性布局 :
Row/Column - 相对 / 层叠布局 :
Stack + Positioned | Align - 滚动 :
SingleChildScrollView、ListView、CustomScrollView - 列表 :
ListView.builder最普遍;AnimatedList、ReorderableListView提供更高阶交互 - 点击 & 动态更新 :
InkWell/GestureDetector+setState(),或选择更合适的状态管理/动画组件
| Android 组件 / 布局 | Flutter 对应 Widget | 备注与补充 |
|---|---|---|
| LinearLayout (vertical / horizontal) | Column / Row |
线性排列;用 Expanded / Flexible 实现权重,Spacer 占位 |
| RelativeLayout / FrameLayout | Stack + Positioned / Align |
层叠摆放、支持绝对或相对父布局定位 |
| ConstraintLayout | Stack + 约束插件(flutter_layout_grid / flutter_constraintlayout) 或直接拆分为多层 Row / Column / Expanded |
官方无完全等价物,复杂场景可引入第三方 |
| ScrollView | SingleChildScrollView |
仅能包裹单个子组件(可再套 Column 等) |
| NestedScrollView | NestedScrollView(Flutter 同名) 或 CustomScrollView + SliverAppBar/SliverList |
协同滚动吸顶效果 |
| ListView (Adapter) | ListView.builder |
懒加载;itemBuilder 相当于 Adapter |
| RecyclerView + DiffUtil | ListView.builder + AnimatedList / 第三方 flutter_staggered_grid_view |
默认已复用 item,无需 ViewHolder;动画用 AnimatedList |
| GridView | GridView.count / GridView.builder |
crossAxisCount、SliverGridDelegate 控制列数与间距 |
| ViewPager / ViewPager2 | PageView |
支持横纵向、无限轮播(配合 PageController) |
| TabLayout + ViewPager | TabBar + TabBarView |
TabController 关联 |
| DrawerLayout | Scaffold.drawer / Scaffold.endDrawer |
自动处理滑动抽屉 |
| Toolbar / AppBar | AppBar(Scaffold.appBar) |
内建返回按钮、菜单 |
| FloatingActionButton | FloatingActionButton(同名) |
放在 Scaffold.floatingActionButton |
| CardView | Card |
带圆角与阴影 |
| Snackbar | SnackBar |
ScaffoldMessenger.of(context).showSnackBar() |
| AlertDialog | AlertDialog |
showDialog(context: ...) |
Switch (SwitchCompat) |
Switch / SwitchListTile |
|
| CheckBox / RadioButton | Checkbox / Radio (RadioListTile) |
|
| EditText | TextField / TextFormField |
输入装饰用 InputDecoration |
| ProgressBar | CircularProgressIndicator / LinearProgressIndicator |