提示信息
# 同伴 App — 组件快速参考表
> 新建页面前先查这里,优先使用已有组件,禁止重复手写样式。
---
## 一、新建页面 SOP(10 步)
```
1. Scaffold + AppNavBar(不用原生 AppBar)
2. body 用 SafeArea / ListView 包裹内容
3. 加载态用 AppSkeleton.wrap(enabled: isLoading, child: ...)
4. 空/错误态用 AppEmptyState(type: ...)
5. 列表行用 AppCell,不用 ListTile
6. 输入框用 AppInput,不用 TextField
7. 主按钮用 PrimaryActionButton,次要文字用 text.onTap()
8. 提示用 AppToast,弹窗用 AppDialog.show/showSheet
9. 滑动操作用 AppSwipeCell
10. 分割线用 AppDivider / AppDivider.indent() / AppDividerLabel()
```
---
## 二、完整组件速查表
### 导航
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `AppNavBar` | 顶部导航栏(所有页面) | `title`, `showBack`, `actions`, `showDivider` | `AppNavBar(title: '标题')` |
| `AppTransparentNavBar` | 叠在图片/渐变上的透明导航 | `title`, `scrollController`(必传) | `AppTransparentNavBar(title: '详情', scrollController: _sc)` |
| `AppSearchNavBar` | 搜索导航栏 | `onSubmitted`(注意不是 onSearch) | `AppSearchNavBar(onSubmitted: (q) => search(q))` |
| `AppChatNavBar` | 聊天输入栏 | `actions`(注意不是 onMoreTap) | 见 chat_page |
| `AppBottomNavBar` | 底部 Tab 栏(仅 main_shell) | 3 个 tab 固定,不做参数化 | 见 main_shell_page |
---
### 反馈与通知
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `AppToast.showSuccess` | 成功提示(顶部滑入,2.5s) | `message` | `AppToast.showSuccess('保存成功')` |
| `AppToast.showError` | 错误提示 | `message` | `AppToast.showError('网络异常')` |
| `AppToast.showWarning` | 警告提示 | `message` | `AppToast.showWarning('操作不可逆')` |
| `AppToast.showInfo` | 信息提示 | `message` | `AppToast.showInfo('功能开发中')` |
| `AppDialog.show` | 确认弹窗(居中,内部按钮 44dp,比主操作按钮小一号) | `context`, `content`, `isDestructive` | `AppDialog.show(context: context, content: '确认删除?', isDestructive: true)` |
| `AppDialog.showSheet` | 底部弹出表单(默认内边距 h:24 top:16 bottom:24) | `context`, `title?`, `child`, `padding?` | `AppDialog.showSheet(context: context, child: MySheet())` |
| `AppActionSheet` | iOS 风格操作菜单 | `context`, `actions` | `AppActionSheet.show(context: context, actions: [...])` |
| `AppLoading.show/hide` | 全屏遮罩加载 | `context` | `AppLoading.show(context)` → 完成后 `AppLoading.hide(context)` |
---
### 加载 / 空状态
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `AppSkeleton.wrap` | 骨架屏(推荐) | `enabled`, `child` | `AppSkeleton.wrap(enabled: isLoading, child: RealWidget())` |
| `AppSkeleton.fromWidget` | loading 分支骨架屏 | `child`(占位结构) | `loading: () => AppSkeleton.fromWidget(child: _placeholder())` |
| `AppSkeleton.listTile` | 列表行占位 | — | `AppSkeleton.listTile()` |
| `AppSkeleton.card` | 卡片占位 | — | `AppSkeleton.card()` |
| `AppEmptyState` | 空/错误状态页 | `type`, `onAction?`, `actionLabel?` | `AppEmptyState(type: AppEmptyType.noData, onAction: () => ref.refresh(p))` |
**AppEmptyType 枚举:**
`noData` / `networkError` / `serverError` / `searchEmpty` / `noMessage` / `noNotification` / `permissionDenied` / `custom`
---
### 列表与单元格
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `AppCell` | 通用列表行(min-h 56dp,含 AppSwitch trailing 不会撑高) | `title`, `subtitle?`, `icon?`, `value?`, `onTap?`, `trailing?`, `showArrow?` | `AppCell(title: '账号与安全', icon: AppIcons.shield, onTap: () => context.push(...))` |
| `AppSwipeCell` | 滑动操作行 | `child`, `actions` | 见 signal_inbox_page |
| `AppListView` | 优化列表容器 | Flutter ListView 相同 API | `AppListView(children: [...])` |
---
### 表单与输入
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `AppInput` | 文本输入框 | `controller`, `placeholder`, `label?`, `errorText?`, `suffix?`, `maxLines?` | `AppInput(controller: _ctrl, placeholder: '请输入内容')` |
| `AppCheckbox` | 复选框 | `value`, `onChanged`, `size?` | `AppCheckbox(value: isSelected, onChanged: (v) => setState(()=> isSelected=v))` |
| `AppRadio` | 单选按钮 | `value`, `groupValue`, `onChanged` | `AppRadio(value: 'a', groupValue: selected, onChanged: (v) => ...)` |
| `AppSwitch` | 开关(CupertinoSwitch 风格,固定 iOS 绿 #34C759) | `value`, `onChanged`, `activeColor?` | `AppSwitch(value: enabled, onChanged: (v) => ...)` |
| `AppTag` | 可选择标签(选中=主题色12%透明bg+主题色文字+30%透明描边;分类色:传 selectedColor) | `label`, `selected`, `onTap`, `selectedColor?` | `AppTag(label: '恋爱', selected: isSelected, onTap: () => ...)` |
| `AppIdCardKeyboard` | 自定义数字键盘 | `onKeyTap`, `onDelete`, `onClear` | 见 verification_page |
---
### 按钮
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `PrimaryActionButton` | 主操作按钮(全宽渐变) | `text/label`, `onTap/onPressed`, `isSecondary?`, `isDestructive?`, `enabled?` | `PrimaryActionButton(text: '提交', onTap: () async => submit())` |
| `AppCapsuleButton` | 胶囊按钮(社交关注等) | `label`, `isFollowing`, `onTap` | `AppCapsuleButton(label: '关注', onTap: () => ...)` |
| 文字操作按钮 | 次要文字链接(代替 TextButton) | VelocityX 链式 | `'查看详情'.text.color(context.themeAccent).make().onTap(() => ...)` |
---
### 头像与徽章
| 组件 | 用途 | 关键参数 | 最小示例 |
|------|------|---------|---------|
| `CustomAvatar` | 用户头像(支持网络/本地/文字) | `url`, `name`, `size` | `CustomAvatar(url: user.avatar, name: user.nickname, size: AvatarSize.df)` |
| `AppBadge` | 消息徽章 | `count`, `child` | `AppBadge(count: 5, child: Icon(AppIcons.notification))` |
**AvatarSize:** `sm`(32) / `df`(48) / `lg`(64) / `xl`(80) / `xxl`(120)
---
### 分割线
| 组件 | 用途 | 最小示例 |
|------|------|---------|
| `AppDivider()` | 全宽分割线 | `const AppDivider()` |
| `AppDivider.indent(left: 52)` | 带缩进(列表行默认52dp) | `const AppDivider.indent()` |
| `AppDividerLabel('或者')` | 文字居中分割线 | `AppDividerLabel('或者')` |
---
### 其他
| 组件 | 用途 | 最小示例 |
|------|------|---------|
| `AppTabBar` | 页面内 Tab 切换 | 见 component_showcase_page |
| `AppSheet` | 底部弹层基础容器 | 一般通过 `AppDialog.showSheet` 调用 |
| `EditorialWidgets` | 内容卡片(信号/动态) | 见 signal_detail_page |
---
## 三、全局形状模式
**当前支持三种全局形状**(在设置 → 显示中切换):
| 模式 | 枚举值 | 按钮 | 输入框 | 标签 | 卡片 |
|------|--------|------|--------|------|------|
| 标准圆角(默认) | `AppShapeMode.rounded` | 12dp | 12dp | 8dp | 16dp |
| 方直 | `AppShapeMode.square` | 4dp | 4dp | 4dp | 4dp |
| 胶囊 | `AppShapeMode.pill` | 全圆 | 12dp | 全圆 | 16dp |
**组件内读取方式:**
```dart
context.appButtonRadius // 按钮圆角
context.appInputRadius // 输入框圆角
context.appTagRadius // 标签圆角
context.appCardRadius // 卡片圆角
```
---
## 四、颜色速查(动态深浅色)
```dart
// 文字
context.themeTextPrimary // 主文字
context.themeTextSecondary // 次要文字
context.themeTextHint // 占位/提示
// 背景
context.themeBackground // 页面背景
context.themeSurface // 卡片/模块
context.themeCard // 嵌套卡片
context.themeDivider // 分割线/边框
context.themeInputBg // 输入框背景
context.themeAccent // 操作色(砖红/金)
context.themeError // 错误色
// 静态语义色(用于 AppSwitch 激活色等)
AppColors.success // #34C759 iOS绿(AppSwitch 默认激活色)
AppColors.warning // #FF9500 橙
AppColors.error // #FF3B30 红
```
---
## 五、常见错误对照
| ❌ 禁止 | ✅ 正确 |
|--------|--------|
| `AppBar(title: Text('标题'))` | `AppNavBar(title: '标题')` |
| `ListTile(title: Text('设置'))` | `AppCell(title: '设置')` |
| `showModalBottomSheet(...)` | `AppDialog.showSheet(context: context, child: ...)` |
| `showDialog(...)` | `AppDialog.show(context: context, content: '...')` |
| `ScaffoldMessenger.of(ctx).showSnackBar(...)` | `AppToast.showSuccess/Error/Warning/Info('...')` |
| `CircularProgressIndicator()` (页面级) | `AppSkeleton.wrap(enabled: isLoading, child: ...)` |
| `TextField(...)` | `AppInput(controller: ..., placeholder: '...')` |
| `ElevatedButton(...)` | `PrimaryActionButton(text: '...', onTap: ...)` |
| `TextButton(onPressed: f, child: ...)` | `'文字'.text.color(...).make().onTap(f)` |
| `Divider(color: context.themeDivider)` | `AppDivider()` |
| `Badge(count: n, child: ...)` | `AppBadge(count: n, child: ...)` |
| `Navigator.push(...)` | `context.push(AppRoutes.xxx)` |