ArkUI Grid:折叠屏图库滑动多选稳定ID与布局切换【鸿蒙心迹】
相册类应用做成两列网格并不难真正容易出问题的是用户正在批量选图的时候把折叠屏展开。折叠前第三张照片在第二行展开后同一张可能移到第一行如果业务把“第几个格子被选中”作为记录布局重排以后勾选标记就会落到另一张照片上。更尴尬的是页面明明还显示“已选择 3 张”底部导出拿到的却不是刚才圈中的那三张。这次把问题放进一个小工程PhotoBatch。它不是大型图库也没有接入相册媒体库只用八张带稳定业务 ID 的示例素材固定选择P102、P104、P107选择数量为3。界面有2 列 / 4 列两种排版展开态展示四列编辑状态叫EDITING。讨论重点是三件事谁保管选中结果、网格重排怎样处理、离开编辑模式该不该清空它。图 01两列与四列布局切换的概念封面。示例配图用于解释稳定 ID不代表实机折叠动作已经测试。## 一、我不想再让数组下标承担业务身份如果收藏列表永远不插入、不删除、不排序索引看起来非常方便。selectedIndexes [1, 3, 6]能在当下圈出三张图。可一旦切换排序方式甚至只是让用户从大屏换到小屏重新加载数据下标就只能描述一个位置不能描述一张具体照片。位置由布局决定身份则应该由业务数据决定把二者绑在一起迟早会有问题。ArkUI 的 Grid/GridItem 提供了网格展示和选择状态回调华为官方创建网格文档还特别提示选择记录建议使用不会随位置变化的唯一标识。文档记载自 API 26.0.0 起 Grid 支持编辑模式下的手指滑动多选包括enableEditMode、editModeOptions、selectable、selected与onSelect。这意味着功能不能无条件宣称覆盖所有旧系统。需要照顾更早目标版本的产品可以先采用普通点击选中再按设备能力逐步增加滑动多选。https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/arkts-layout-development-create-grid先把示例数据和选中集合写成可测试的纯业务模型。这段代码要解决的问题是布局怎么变化都以照片 ID 判断是否选中并在数据刷新时剔除已不存在的 ID。arktsinterface PhotoAsset { id: string title: string}class PhotoSelection { private ids: Setstring new Setstring() setSelected(id: string, value: boolean): void { if (value) this.ids.add(id) else this.ids.delete(id) } has(id: string): boolean { return this.ids.has(id) } snapshot(): string[] { return Array.from(this.ids.values()) } reconcile(assets: PhotoAsset[]): string[] { const alive new Setstring(assets.map((p: PhotoAsset): string p.id)) this.ids.forEach((id: string) { if (!alive.has(id)) this.ids.delete(id) }) return this.snapshot() }}Set 适合存“已经选择了哪些照片”但不意味着可以直接把一个原地修改的 Set 扔进任意状态装饰器就期待 UI 自动重绘。业务层保管集合展示层每次收到变化后取出新数组赋给 State更容易观察状态更新。reconcile() 也不是强行取消所有选择它仅处理已从当前素材集合中消失的 ID如果图库采用分页模式还要区分“当前页没加载到”和“业务记录已经被删除”不能对分页列表直接做全量回收。## 二、选中态留在业务里网格只负责表达GridItem 知道自己能否被选中也会在用户切换选择时给出一个布尔值。它不必知道“这张照片在整个项目里排第几”。当 columnsTemplate 从两列改成四列Grid 重新排布子项当前图片仍然以 P102 等 ID 去读取业务记录视觉勾选就能找回正确对象。下面是页面的关键结构。代码解决的是把官方的编辑模式回调与自己的选中账本连接起来而不是实现一套新的手势识别器。真实工程需配合完整的资源文件、页面容器和图项 Builder这里用文字卡片缩小代码范围。arktsEntryComponentstruct PhotoBatchPage { State columns: number 4 State editMode: boolean true State chosen: string[] [‘P102’, ‘P104’, ‘P107’] private assets: PhotoAsset[] [ { id: ‘P101’, title: ‘雪山’ }, { id: ‘P102’, title: ‘花朵’ }, { id: ‘P103’, title: ‘湖泊’ }, { id: ‘P104’, title: ‘森林’ }, { id: ‘P105’, title: ‘海岸’ }, { id: ‘P106’, title: ‘城市’ }, { id: ‘P107’, title: ‘草地’ }, { id: ‘P108’, title: ‘建筑’ } ] private select(id: string, value: boolean): void { this.chosen value ? […new Set([…this.chosen, id])] : this.chosen.filter((key: string): boolean key ! id) } build() { Column() { Text(已选择 ${this.chosen.length} 张) Grid() { ForEach(this.assets, (item: PhotoAsset) { GridItem() { Text(${item.id} ${item.title}) } .selectable(true) .selected(this.chosen.includes(item.id)) .onSelect((selected: boolean) this.select(item.id, selected)) }, (item: PhotoAsset): string item.id) } .columnsTemplate(this.columns 4 ? ‘1fr 1fr 1fr 1fr’ : ‘1fr 1fr’) .enableEditMode(this.editMode) .onEditModeChange((enabled: boolean) { this.editMode enabled }) .editModeOptions({ useDefaultMultiSelectStyle: true, enableTwoFingerMultiSelect: true }) } }}这段代码假设项目的 SDK 和运行设备具备相应 Grid 编辑模式能力不能直接拿到旧版工程中宣称通用。State chosen 是新的数组减少框架感知不到内部集合变化的风险。ForEach 使用唯一 ID 作 key而不是索引否则同一业务记录被移动到其他位置时组件复用和勾选样式可能互相影响。示例中第一次打开就预置了三个选中值目的是让图片、日志与状态一致不是在暗示系统默认会替用户选图。![](https://i-blog.csdnimg.cn/direct/a8bb927fd6ef4f6eb6a40d2b511deab2.png)*图 02独立制作的 DevEco Studio 风格示意图右侧模拟器显示四列布局与 P102/P104/P107 三项选择底部 HiLog 为预设的教学日志不是真实设备采集证据。*## 三、布局改变是一件事编辑会话结束是另一件事从折叠态的 2 列切到展开态的 4 列我希望视觉重新计算不希望业务 ID 集合发生变化。这个区分可以用一个极小的方法表达输入最新有效宽度只改变列数不碰 chosen。宽度最好来自实际容器的测量值而不是仅根据设备型号猜测“展开”。分屏、悬浮窗口和横竖屏变化同样可能改变可用区域。第三段代码专门用于处理这个边界。这里的 600vp 是 Demo 人为选择的阈值不是官方规定的折叠屏分界线。阈值要由真实页面最小卡片宽度、留白和字体测量共同决定。arktsprivate adaptColumns(widthVp: number): void { if (!Number.isFinite(widthVp) || widthVp 0) return const next widthVp 600 ? 4 : 2 if (next ! this.columns) { this.columns next console.info([PhotoBatch] columns${next} selected${this.chosen.join(,)}) }}// 挂到实际需要测量的容器上// .onAreaChange((_old: Area, now: Area) {// this.adaptColumns(Number(now.width))// })开发图使用展开态columns4日志写明selectedP102,P104,P107。把屏幕缩回两列后应该仍然是这三个 ID唯一变化是卡片在网格中的位置。编辑模式结束则由产品决定是否清空如果底部操作栏只是暂时收起我倾向于保留选择待用户明确点击“取消选择”才清除如果进入新相册则应按相册会话创建新的集合。不要把onEditModeChange(false)简单等同于清空因为系统返回和手势也可能导致编辑模式变化。## 四、先看可验证的状态再谈操作手感本文演示态固定为PhotoBatch任务编号BATCH_20261016_15状态EDITING已选择 3 张、当前四列。手机界面示意展示三个绿色勾选标识底部操作入口是“导出所选”和“取消选择”。数据只表达选中不代表真的把相册文件导出到了磁盘。类似批量删除、批量共享这样的操作都应该在业务层二次确认选中的 ID 是否仍然有效。*图 03纯屏图库界面示意。实际项目应继续使用屏幕朗读工具核对复选标记名称并在真机上观察双指进入编辑模式的手势冲突。*怎样检查这个功能我会做一个很朴素的顺序先选三张再从两列改为四列确认选中 ID 没变插入一张新照片确认原有选择没有偏移从列表中真正删除一项再用reconcile()清理该项最后退出编辑模式并重新进入核对产品定义的保留策略。测试日志应同时打印业务 ID 和列数避免只记录“选中数量 3”却无法判断选中对象是否正确。这里还要注意Grid 的“滑动多选”并非免费的所有场景都适用。卡片内部如果有横向轮播、拖拽排序、长按菜单多种手势会竞争触摸事件。官方文档也提到了自定义样式下的手势裁决。最安全的路径是先保留系统默认多选样式在确实需要自定义时再逐项验证手势热区、辅助功能和低版本兼容行为。## 五、状态稳定比布局漂亮更重要这套方案的核心不是“从两列变四列”这种效果而是让布局变化只影响几何分配让业务 ID 决定每一张照片的身份。它适用于折叠屏图库、平板素材管理以及窗口大小可变化的文件选择器却不覆盖媒体访问权限、云相册同步冲突也不解决跨设备事务一致性。实现落地前还需要在目标 SDK 下编译enableEditMode等接口对低版本设置明确的交互降级策略。本文配图为演示素材示例未在真实 DevEco 项目或设备上运行。把“布局策略”和“选中集合”这两条线分清才不容易在多形态适配时把旧问题重新带回来。

相关新闻

深度学习训练全流程排查:从数据预处理到模型评估的实践指南

深度学习训练全流程排查:从数据预处理到模型评估的实践指南

从上次整理完第一份深度学习笔记到现在,隔了挺长时间。这段时间里我自己试了不少网络结构,也帮身边几个在做项目的同学盯过他们的训练过程,发现一个特别常见的现象:论文里的模型看着都懂,跑开源代码也能出结果&#xf…

2026/10/16 21:20:40 阅读更多 →
井震联合字典学习:稀疏表示实现地震数据高分辨率重建

井震联合字典学习:稀疏表示实现地震数据高分辨率重建

1. 井震联合字典学习到底在解决什么问题第一次看到"井震联合字典学习"这个组合词,很多人会愣一下:字典学习不是图像处理里的东西吗,怎么跟地震勘探扯上关系了?我当初接手这个方向的时候也有同样的疑问。简单说&#xff…

2026/10/16 21:20:40 阅读更多 →
Learun7.Ultimate低代码平台实战:从权限配置到流程部署避坑指南

Learun7.Ultimate低代码平台实战:从权限配置到流程部署避坑指南

简介:力软7.0.Ultimate是一套面向软件开发者和IT专业人士的综合开发框架源码,涵盖前端UI、后端服务、数据库访问、安全控制等模块,适用于快速构建Web应用与复杂业务系统。资源共包含2000个文件,压缩包大小约113.21MB,主…

2026/10/16 21:20:40 阅读更多 →

最新新闻

Python爬虫实战:从网页剖析到数据落库的完整路径

Python爬虫实战:从网页剖析到数据落库的完整路径

简介:Python网络数据抓取代码是一份面向Python初学者的爬虫与数据采集实践包,适合数据分析师、数据科学家、机器学习与自然语言处理方向入门者自学,也可用于网站内容采集、电商信息监控、舆情监测、市场调研等典型任务。资源围绕网络请求、页…

2026/10/16 21:58:15 阅读更多 →
Linux防火墙完全配置指南:iptables、firewalld与ufw详解

Linux防火墙完全配置指南:iptables、firewalld与ufw详解

1. 为什么Linux服务器需要防火墙:先弄清楚它在挡什么先讲一个我实际遇到过的场景。某开发者给公司内部部署了一套应用,把服务跑在8080端口,自以为端口开了就万事大吉。结果第二天用户反馈访问不了——排查到最后才发现,云厂商安全…

2026/10/16 21:58:15 阅读更多 →
信息学奥赛课课通C++配套资料:用好测试数据从不浪费题库

信息学奥赛课课通C++配套资料:用好测试数据从不浪费题库

简介:《信息学奥赛课课通(C)》完整配套资料包,面向准备参加信息学竞赛(NOIP、CSP等)的中学生和C初学者,内容系统覆盖C语法基础、STL容器、面向对象编程及搜索排序等竞赛常考算法。整个rar压缩包…

2026/10/16 21:58:15 阅读更多 →
Cesium 入门指南:从三维地球到 WebGIS 开发的完整教程

Cesium 入门指南:从三维地球到 WebGIS 开发的完整教程

简介:面向具备一定Web前端基础、希望入门三维地球开发的技术人员,这份Cesium学习教程PPT以入门级教学为核心,系统梳理了从开发环境搭建到核心API应用的全流程,可帮助开发团队快速搭建虚拟地球Web应用。内容从Node、VSCode、Nginx等…

2026/10/16 21:58:15 阅读更多 →
Logistic回归二分类实验全复盘:从原理推导到PyTorch实现

Logistic回归二分类实验全复盘:从原理推导到PyTorch实现

实验三的任务是logistic回归预测二分类。说实话,刚开始我有点看不上这个实验,毕竟周围同学已经开始讨论各种“网络结构”了,而我还在跟一条S曲线打交道。但真正把代码跑起来、把loss曲线拉出来看之后,我的想法完全变了。这个实验表…

2026/10/16 21:58:15 阅读更多 →
TurboVLA 0.2B模型如何实现32Hz实时推理与0.9GB显存优化

TurboVLA 0.2B模型如何实现32Hz实时推理与0.9GB显存优化

1. TurboVLA 到底解决了什么问题第一次看到“0.2B 参数、32Hz 实时推理、RTX 4090 只占 0.9GB 显存”这组数字,我的反应是:这要么是标题党,要么是在某个特定任务上做了极致裁剪。因为按常规经验,一个 0.2B 的模型想在消费级卡上跑…

2026/10/16 21:57:14 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →