【OpenHarmony/HarmonyOs 】ArkUI 宫格与列表双视图切换,并用 Preferences 记住选择
【OpenHarmony/HarmonyOs 】ArkUI 宫格与列表双视图切换,并用 Preferences 记住选择
前言
同一组网站,用户可能喜欢图标密集的宫格,也可能更习惯展示完整网址的列表。LinkOS 链界首页提供 grid/list 双视图,并把选择保存到 Preferences,使应用重启后仍保持上次布局。本文讲清状态建模、条件渲染、持久化和响应式细节。🧩
一、视图模式应该是受限类型
@State viewMode: 'grid' | 'list' = 'grid';
使用字符串联合类型比普通 string 更安全。编译器可以阻止 gird 之类拼写错误,代码补全也更准确。
如果模式继续增加,可使用枚举或常量:
export class HomeViewMode {
static readonly GRID = 'grid';
static readonly LIST = 'list';
}
二、用状态驱动分支布局
if (this.viewMode === 'grid') {
Grid() {
ForEach(this.getFilteredSites(), (item: UrlItem) => {
GridItem() { this.SiteCard(item) }
})
GridItem() { this.AddSiteCard() }
}
.columnsTemplate('1fr 1fr')
.columnsGap(12)
.rowsGap(12)
} else {
List() {
ForEach(this.getFilteredSites(), (item: UrlItem) => {
ListItem() { this.SiteListRow(item) }
})
ListItem() { this.AddSiteCard() }
}
}
数据源和筛选函数保持一致,只替换表现层。不要分别维护 gridSites 与 listSites,否则收藏、搜索和删除后容易出现两份状态不同步。
三、切换控件与选中反馈
Button('▦')
.fontColor(this.viewMode === 'grid' ? '#615FFF' : '#6A7282')
.onClick(async () => {
this.viewMode = 'grid';
await StorageUtil.getInstance().put(
StorageKeys.HOME_VIEW_MODE,
this.viewMode
);
})
两个图标按钮应该有固定宽高、明确选中态和辅助说明。颜色不是唯一反馈,建议同时改变背景或增加选中指示,并为图标提供无障碍文本。
四、恢复用户上次选择
const storedMode = await storage.get(
StorageKeys.HOME_VIEW_MODE,
'grid'
) as string;
this.viewMode = storedMode === 'list' ? 'list' : 'grid';
不要直接把磁盘字符串断言成联合类型。旧版本、调试数据或未来迁移都可能产生非法值。读取后做白名单校验,未知值回退到默认宫格。
五、写入失败如何处理
切换布局应先更新 UI,再异步保存。即使磁盘写入失败,用户本次操作仍可立即生效:
private async changeViewMode(mode: 'grid' | 'list'): Promise<void> {
this.viewMode = mode;
await StorageUtil.getInstance().put(StorageKeys.HOME_VIEW_MODE, mode);
}
如果 StorageUtil 吞掉错误,页面无法提示保存失败。对于非关键偏好可以接受静默降级;对于关键业务数据则应让 Service 返回失败状态。
六、宫格和列表的信息密度
宫格适合:图标识别、快速扫描、内容较少。列表适合:长标题、完整 URL、编辑删除和更多元数据。双视图不应只是把卡片拉长,而应针对场景调整内容:
| 内容 | 宫格 | 列表 |
|---|---|---|
| 图标 | 更大 | 较小 |
| URL | 省略或隐藏 | 单行展示 |
| 标签 | 1 个 | 可展示多个 |
| 编辑操作 | 菜单 | 行尾按钮 |
| 每屏数量 | 较多 | 较少 |
七、响应式列数
固定两列只适合手机。项目支持 tablet 和 2in1,可按窗口宽度选择列模板:
手机窄屏:2 列
平板竖屏:3 列
平板横屏/2in1:4 至 6 列,并限制卡片最大宽度
宽屏不要无限拉宽单个卡片,否则文字行长和视觉比例都会失衡。
八、切换时保持阅读位置
用户在列表中滚动到很后面再切换宫格,如果直接回顶部会比较突兀。可以记录当前首个可见项 ID,并在新布局构建后滚动到相同项目。比记录像素偏移更可靠,因为两种布局高度不同。
九、状态来源与性能
getFilteredSites() 可能同时受搜索词、分类、自定义数据和视图模式影响。视图模式不应该触发重新请求数据,只改变组件树。大量数据时,应使用稳定 ID,并避免在构建过程中反复进行昂贵排序。
十、测试要点 ✅
- 初次安装默认宫格;
- 切换列表后重启仍是列表;
- Preferences 存在非法值时回退宫格;
- 搜索、删除和新增在两种模式结果一致;
- 空状态与“添加网站”入口都能显示;
- 平板宽屏列数合理;
- 快速连续切换不会产生异常写入。
十一、总结
双视图功能的关键是“同一数据源、两种表现、一个持久化偏好”。用联合类型限制状态,用条件渲染切换 Grid/List,读取 Preferences 时进行白名单校验,再针对不同布局重新安排信息密度,才能让切换真正提升效率。✨

更多推荐


所有评论(0)