flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
# 【Demo】Stack + Positioned 层叠布局
> 源文件:`lib/pages/demo/stack_demo.dart` | 分类:基础布局
> 一句话:UI 重叠 = CSS 的 `position: absolute`,本页附赠一个真实踩过的"全 Positioned 尺寸崩溃"大坑。
---
## 一、这个 Demo 解决什么问题
做"头像 + 右上角角标"、"卡片 + 半透明蒙层"、"悬浮按钮"这类**元素重叠**的 UI。
Flutter 用 `Stack` 实现:
- `Stack` = 图层容器(**后写的子组件盖在上面**);
- `Positioned` = 给子组件做绝对定位(**只能直接放在 Stack 的 children 里**)。
---
## 二、怎么运行 / 演示内容
```dart
runApp(const MaterialApp(home: StackDemoPage()));
```
页面演示 5 块内容:
1. 基础重叠:蓝色盒子 + 右上角悬空角标 + 居中文字;
2. `Positioned.fill` 半透明蒙层;
3. 坑①复现:全 Positioned 时 Stack 尺寸异常;
4. 修复方案 1:SizedBox 固定宽高;
5. 修复方案 2:非 Positioned 底层组件撑尺寸。
---
## 三、核心知识点(新手向)
### 1. Stack 的两个核心参数
```dart
Stack(
alignment: Alignment.topLeft, // 对【没被 Positioned 包裹】的子组件做默认对齐
clipBehavior: Clip.none, // 允许子组件绘制超出 Stack 边界(默认 Clip.hardEdge 会裁剪)
children: [...],
)
```
### 2. Positioned 的用法
```dart
Positioned(
top: 10, // 距 Stack 上边
right: -10, // 负值 = 超出边界(配合 clipBehavior: Clip.none 才能显示)
child: ...,
)
Positioned.fill( // 填满整个 Stack —— 做蒙层最方便
child: Container(color: Colors.black54),
)
```
### 3. 布局规则一句话
Stack 的尺寸 = **非 Positioned 子组件**决定的(取其中最大的那个);
Positioned 组件只是"贴"在上面,不参与 Stack 自身尺寸计算。
---
## 四、关键代码剖析(含大坑)
### 坑①:全部子组件都是 Positioned → Stack 尺寸异常
```dart
// 真实行为:Stack 尺寸不由内容决定,直接取父约束最大值(constraints.biggest)
Stack(
children: [
Positioned(top: 10, left: 10, child: Text("A")),
],
)
```
- 放在**有界约束**里(如 SizedBox 300×60)→ Stack 占满整个 300×60,而不是收缩到文字大小;
- 裸放在 **Column 等无界高度**里 → debug 模式直接断言崩溃:
`A Stack requires bounded constraints`,**整个 body 都画不出来**(只看到标题栏)。
### 修复方案 1:给 Stack 套 SizedBox 固定宽高
```dart
SizedBox(
width: 300.w,
height: 80.h,
child: Stack(children: [Positioned(top: 10, left: 10, child: Text("A"))]),
)
```
### 修复方案 2:放一个非 Positioned 的底层组件撑起大小
```dart
Stack(
children: [
ColoredBox( // 非 Positioned 底层组件:由它决定 Stack 尺寸
color: Color(0xFFE8E8E8),
child: SizedBox(width: 300.w, height: 80.h),
),
Positioned(top: 10, left: 10, child: Text("A")),
],
)
```
> 经验:**Stack 里永远留一个"地基"**(非 Positioned 的底层组件或外层 SizedBox),
> 既避免崩溃,也方便后续加 Positioned 不担心尺寸突变。
---
## 五、踩坑记录
1. **Positioned 只能直接作为 Stack 的 children**,中间套了其他 Widget 会失效(编译警告)。
2. **做悬浮角标务必 `clipBehavior: Clip.none`**,否则负偏移部分被裁掉看不见。
3. **全 Positioned 的 Stack 在无界约束下崩溃**(见上),这是本页作者真实遇到过的 bug:页面只剩标题。
4. `Container` 在 Flutter 3.44 已不是 const 构造,外层 `Center` 别写 `const`(编译报错)。
5. 想让内容很短也能拉动滚动(演示页效果),用 `physics: BouncingScrollPhysics()` / `AlwaysScrollableScrollPhysics()`。
---
## 六、扩展思考
- 蒙层进阶:`Positioned.fill` + 半透明色 + 点击手势 = 简易弹窗/引导层;
- 角标进阶:红点角标(Badge 组件)本质也是 Stack + Positioned 的封装;
- 与 [list_demo.md](list_demo.md) 对照:列表右下角的"回到顶部"FAB 就是 `Stack + Positioned` 实现的;
- 与 [smooth_sheet_demo.md](smooth_sheet_demo.md) 对照:地图背景 + 底部面板就是"Stack 背景层 + 面板层"的组合。