【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() }
  }
}

数据源和筛选函数保持一致,只替换表现层。不要分别维护 gridSiteslistSites,否则收藏、搜索和删除后容易出现两份状态不同步。

三、切换控件与选中反馈

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 列
平板横屏/2in146 列,并限制卡片最大宽度

宽屏不要无限拉宽单个卡片,否则文字行长和视觉比例都会失衡。

八、切换时保持阅读位置

用户在列表中滚动到很后面再切换宫格,如果直接回顶部会比较突兀。可以记录当前首个可见项 ID,并在新布局构建后滚动到相同项目。比记录像素偏移更可靠,因为两种布局高度不同。

九、状态来源与性能

getFilteredSites() 可能同时受搜索词、分类、自定义数据和视图模式影响。视图模式不应该触发重新请求数据,只改变组件树。大量数据时,应使用稳定 ID,并避免在构建过程中反复进行昂贵排序。

十、测试要点 ✅

  • 初次安装默认宫格;
  • 切换列表后重启仍是列表;
  • Preferences 存在非法值时回退宫格;
  • 搜索、删除和新增在两种模式结果一致;
  • 空状态与“添加网站”入口都能显示;
  • 平板宽屏列数合理;
  • 快速连续切换不会产生异常写入。

十一、总结

双视图功能的关键是“同一数据源、两种表现、一个持久化偏好”。用联合类型限制状态,用条件渲染切换 Grid/List,读取 Preferences 时进行白名单校验,再针对不同布局重新安排信息密度,才能让切换真正提升效率。✨

img

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐