Stack
Stack 将子组件层叠在一起(类似 CSS 的 absolute positioning)。
构造函数
dart
Stack({
Key? key, // 组件标识
AlignmentGeometry alignment = AlignmentDirectional.topStart, // 未定位子组件的对齐方式
TextDirection? textDirection, // 文本方向
StackFit fit = StackFit.loose, // 未定位子组件的尺寸约束
Clip clipBehavior = Clip.hardEdge, // 裁剪行为(超出部分是否裁剪)
List<Widget> children = const [], // 子组件列表(后面的绘制在上层)
})属性速查
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
alignment | AlignmentGeometry | topStart | 未被 Positioned 包裹的子组件的对齐方式 |
textDirection | TextDirection? | null | 文本方向(影响 start/end) |
fit | StackFit | loose | 未定位子组件的尺寸约束策略 |
clipBehavior | Clip | hardEdge | 超出 Stack 边界的子组件是否裁剪 |
children | List<Widget> | [] | 子组件列表,后面的绘制在上层 |
fit 值说明
| 值 | 行为 |
|---|---|
StackFit.loose | 子组件可以从 0 到 Stack 尺寸之间自由选择(默认) |
StackFit.expand | 子组件被强制撑满 Stack |
StackFit.passthrough | 子组件继承 Stack 的约束 |
clipBehavior 值说明
| 值 | 行为 |
|---|---|
Clip.hardEdge | 硬边裁剪(默认) |
Clip.antiAlias | 抗锯齿裁剪 |
Clip.none | 不裁剪,子组件可以溢出显示 |
Positioned — 精确定位
Positioned 用于在 Stack 中精确控制子组件的位置和大小。
构造函数
dart
Positioned({
double? left, // 距左边距离
double? top, // 距顶部距离
double? right, // 距右边距离
double? bottom, // 距底部距离
double? width, // 宽度
double? height, // 高度
required Widget child,
})属性速查
| 属性 | 类型 | 说明 |
|---|---|---|
left | double? | 距左边距离 |
top | double? | 距顶部距离 |
right | double? | 距右边距离 |
bottom | double? | 距底部距离 |
width | double? | 宽度 |
height | double? | 高度 |
child | Widget | 子组件(必填) |
定位规则
| 指定属性 | 效果 |
|---|---|
top + left | 从左上角开始,尺寸由 child 决定 |
left + right | 水平撑满,高度由 child 决定 |
top + bottom | 垂直撑满,宽度由 child 决定 |
left + right + top + bottom | 完全撑满指定区域 |
Positioned.fill() | 四边均为 0,撑满整个 Stack |
快速示例
基本层叠
dart
import 'package:flutter/material.dart';
class StackBasicExample extends StatelessWidget {
const StackBasicExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Stack 基本层叠')),
body: Center(
// ─── ★ Stack 层叠布局 ──────────────
child: Stack(
children: [
// 底层 —— 背景色
Container(
width: 300,
height: 200,
color: Colors.blue,
),
// 顶层 —— 文字
// ─── ★ Positioned 精确定位 ──────────────
const Positioned(
bottom: 16,
left: 16,
child: Text(
'风景照片',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
// ─── ☆ Positioned 精确定位 ──────────────
],
),
// ─── ☆ Stack 层叠布局 ──────────────
),
);
}
}常用定位
dart
// 右上角
Positioned(
top: 10,
right: 10,
child: const Icon(Icons.close),
)
// 底部居中
Positioned(
bottom: 20,
left: 0,
right: 0,
child: ElevatedButton(
onPressed: () {},
child: const Text('操作'),
),
)
// 填充整个区域
Positioned.fill(
child: Container(color: Colors.black.withOpacity(0.5)),
)
// 左半边
Positioned(
left: 0,
top: 0,
bottom: 0,
width: 150,
child: Container(color: Colors.blue.withOpacity(0.3)),
)未定位子组件对齐
dart
Stack(
alignment: Alignment.center, // 未定位子组件居中
children: [
Container(width: 200, height: 200, color: Colors.blue),
const Text('我居中'), // 没有用 Positioned 包裹
],
)常见模式
图片上叠加渐变 + 文字
dart
SizedBox(
width: 300,
height: 200,
child: Stack(
children: [
// 背景图
Image.network(url, fit: BoxFit.cover, width: 300, height: 200),
// 底部渐变遮罩
Positioned.fill(
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.black.withOpacity(0.7), Colors.transparent],
),
),
),
),
// 底部文字
Positioned(
bottom: 16,
left: 16,
right: 16,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('标题', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('副标题', style: TextStyle(color: Colors.white70, fontSize: 14)),
],
),
),
],
),
)头像 + 在线状态指示器
dart
SizedBox(
width: 60,
height: 60,
child: Stack(
children: [
const CircleAvatar(
backgroundImage: NetworkImage(avatarUrl),
radius: 28,
),
Positioned(
bottom: 0,
right: 0,
child: Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
),
),
],
),
)加载中遮罩
dart
Stack(
children: [
// 原有内容
ListView(children: [...]),
// 加载遮罩
if (_isLoading)
Positioned.fill(
child: Container(
color: Colors.black.withOpacity(0.3),
child: const Center(
child: CircularProgressIndicator(),
),
),
),
],
)IndexedStack
IndexedStack 是 Stack 的变体——只显示一个子组件,但保持所有子组件的状态。
构造函数
dart
IndexedStack({
Key? key, // 组件标识
int index = 0, // 当前显示的子组件索引
AlignmentGeometry alignment = AlignmentDirectional.topStart, // 对齐方式
TextDirection? textDirection, // 文本方向
StackFit sizing = StackFit.loose, // 尺寸约束
List<Widget> children = const [], // 子组件列表
})dart
IndexedStack(
index: _currentIndex, // 显示第几个子组件
children: [
const HomeTab(),
const SearchTab(),
const ProfileTab(),
],
)使用场景
适用于底部导航栏切换 Tab 时保持各 Tab 状态(如滚动位置、输入框内容不被丢失)。
Stack vs Column/Row
| 特性 | Stack | Column | Row |
|---|---|---|---|
| 排列方式 | 层叠 | 垂直排列 | 水平排列 |
| 子组件是否重叠 | 可以重叠 | 不重叠 | 不重叠 |
| 定位方式 | Positioned 或 alignment | 主轴/交叉轴对齐 | 主轴/交叉轴对齐 |
