十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【时光清单|05】HarmonyOS ArkTS 倒计时卡片实战:适配 2x2、2x4 与 4x4 多尺寸

【时光清单|05】HarmonyOS ArkTS 倒计时卡片实战:适配 2x2、2x4 与 4x4 多尺寸 【时光清单05】HarmonyOS ArkTS 倒计时卡片实战适配 2x2、2x4 与 4x4 多尺寸桌面卡片不是把应用页面按比例缩小。2x2 只够放一个强数字2x4 可以补充标题和说明4x4 才有空间建立更完整的阅读层级。如果三种尺寸共用一棵拥挤的 UI 树最小尺寸会被迫塞入过多信息如果每种尺寸各自读取数据又容易出现日期算法、默认内容和选中事项不一致。时光清单的真实源码采用了更清晰的结构CountdownFormAbility只负责从纪念日仓库生成统一FormData2x2、2x4、4x4 三个 ArkTS 卡片页面分别通过LocalStorageProp读取数据并独立排版。form_config.json明确注册三个表单分别声明支持尺寸、默认尺寸、颜色模式和更新时间。本文以当前仓库中可读取的真实文件为主线拆解多尺寸卡片的工程方法先统一数据契约再按面积分配信息优先级把更新与降级逻辑放在 FormExtensionAbility最后检查深浅色、长标题、空数据、点击事件和多卡片实例。本文不据此推断未在源码和历史记录中出现的系统版本、运行结果或发布效果。本文会完成这些复核解释应用内CountdownCard与桌面 Form 卡片的职责差异。对比 2x2、2x4、4x4 三种尺寸的真实布局。说明统一FormData如何连接仓库和LocalStorageProp。检查添加、定时更新、选择事项与空数据降级链路。找出点击文案未绑定事件、深色模式和多实例选择的改进点。本文唯一标记CSDN-SERIES:ALL-163202768阅读前先划清证据边界这篇文章把结论分成三类避免把“代码里写了”误写成“设备上已经成功运行”。当前事实来自D:\huawei\one8的静态源码复核。可以确认的是模块注册了一个导出的CountdownFormAbilityform_config.json配置了CountdownSmall、CountdownMedium、CountdownLarge三个独立 ArkTS Form它们分别绑定 2x2、2x4、4x4 页面能力层通过同一getFormData()生成标题、天数、备注和更新时间三个页面按面积选择不同字段。模块的deviceTypes当前只声明phone。历史证据来自项目错误记录。记录表明2026 年 5 月 20 日曾出现“桌面卡片不能选择并显示已有纪念日”的问题原因是组件选择结果没有持久化当时的修复是保存选中 ID并让 Form 读取同一个键。记录还写有当时assembleHap通过但那只是历史检查结果不代表本文写作时重新构建成功更不代表真机、商店审核或线上用户数据已经验证。建议实现是本文在现状之上提出的演进方向包括按formId保存多实例选择、增加日期方向、补齐真实点击事件、使用主题资源、在数据保存后主动请求更新。它们不是当前源码已有能力文中会明确使用“建议”“可以”“如果实现”等表述。下面这份最小清单用于限定本文实际核对的对象entry/src/main/module.json5 entry/src/main/resources/base/profile/form_config.json entry/src/main/ets/forms/CountdownFormAbility.ets entry/src/main/ets/forms/pages/CountdownCard2x2.ets entry/src/main/ets/forms/pages/CountdownCard2x4.ets entry/src/main/ets/forms/pages/CountdownCard4x4.ets entry/src/main/ets/views/WidgetView.ets entry/src/main/ets/components/CountdownCard.ets本文没有执行新的 HAP 构建、安装、桌面添加、06:00 调度、点击跳转或多实例真机测试因此这些项目都保留为待验证项。一、先区分两类卡片应用组件与桌面 Form项目中有两套“倒计时卡片”components/CountdownCard.ets 应用页面内部复用组件 forms/pages/CountdownCard2x2.ets forms/pages/CountdownCard2x4.ets forms/pages/CountdownCard4x4.ets 系统桌面卡片页面应用内组件接收完整AnniversaryComponent export struct CountdownCard { Prop item: Anniversary; onCardClick?: () void; build() { Column() { // 图标、标题、备注、置顶状态和天数 } .onClick(() { if (this.onCardClick) { this.onCardClick(); } }) } }它能访问主题色、资源映射、完整类型和页面回调。桌面 Form 则只消费少量字符串不应把整个领域对象复制进去。两者共享的是日期语义不是 UI 树。二、统一 FormData三种尺寸只拿必要字段CountdownFormAbility定义了窄数据契约interface FormData { title: string; days: string; subtitle: string; updateTime: string; }四个字段分别服务于字段2x22x44x4作用title是是是当前事项名称days是是是强视觉倒计时数字subtitle否是是备注或降级说明updateTime不展示不展示不展示让绑定数据每次带新值2x2 不渲染subtitle但继续接收同一数据对象并没有问题。能力层无需判断尺寸只负责给出完整、稳定、可降级的数据。如果以后 4x4 要展示日期或图标可以扩展可选字段但要保证旧尺寸忽略新字段后仍能正常渲染。三、添加卡片同步读取是为了首帧可用卡片添加时走onAddForm()onAddForm( want: Want ): formBindingData.FormBindingData { hilog.info(0x0000, TAG, onAddForm); const formData this.getFormData(); return formBindingData .createFormBindingData(formData); }getFormData()使用仓库同步入口const repo AnniversaryRepository.getInstance(); repo.initSync(this.context); const items repo.getAllSync();这与应用页面的异步读取不同。Form 添加回调需要立即返回绑定数据项目通过DataStore.initSync(context)读取 Preferences再由仓库执行统一排序。桌面卡片因此不会自行解析 JSON也不会复制“置顶优先、日期升序”的规则。同步读取适合这种小型本地数组。若数据量扩大或迁移到 RDB应评估回调时延并考虑缓存一份专供 Form 的轻量快照。四、选择事项选中 ID 优先否则使用排序第一项能力层读取WIDGET_ANNIVERSARY_IDconst selectedId DataStore.getInstance() .getJsonSyncstring( DataKeys.WIDGET_ANNIVERSARY_ID, ); const selected items.find( (item: Anniversary) item.id selectedId ); const top selected ?? items[0];这条降级链很实用用户选中的事项仍存在时展示它。选中事项被删除时回退到排序后的第一项。没有任何事项时走空数据默认内容。真实仓库的getAllSync()会返回置顶优先、目标日期升序的副本所以items[0]不是随机记录。当前WIDGET_ANNIVERSARY_ID是全局单值。如果用户在桌面添加两个倒计时卡片并希望各自展示不同事项这个模型不够。多实例方案应按formId保存选择export interface FormSelectionMap { [formId: string]: string; } export function getSelectedId( formId: string, selections: FormSelectionMap ): string { return selections[formId] ?? ; }在onRemoveForm(formId)中清理对应映射避免已删除卡片留下无效状态。五、日期语义当前统一显示绝对天数能力层计算const days Math.abs( calcDaysRemaining(top.targetDate) ); const fd: FormData { title: top.title, days: ${days}, subtitle: top.remark ?? 记录重要时刻, updateTime: Date.now().toString() };Math.abs()让未来三天和过去三天都显示数字3。应用内卡片会另外显示“还剩”或“已过去”而桌面 Form 的subtitle来自备注并不包含方向信息。因此当前桌面卡片在目标日期过后可能产生歧义。更完整的数据契约可以增加export type CountdownDirection future | today | past; interface FormDataV2 { title: string; days: string; direction: CountdownDirection; label: string; subtitle: string; updateTime: string; }构造时明确const rawDays calcDaysRemaining(top.targetDate); const direction: CountdownDirection rawDays 0 ? today : rawDays 0 ? future : past; const label direction today ? 就是今天 : direction future ? 还剩 : 已过去;2x2 可以只展示数字与“天”2x4 和 4x4 则加上方向标签。数据语义统一尺寸只决定展示多少。六、2x2数字优先标题退到第三层真实 2x2 页面只读取标题和天数Entry Component struct CountdownCard2x2 { LocalStorageProp(title) title: string 倒计时; LocalStorageProp(days) days: string 0; build() { Column() { Text(this.days) .fontSize(36) .fontWeight(FontWeight.Bold) .fontColor(#2C5F7C) Text(天) .fontSize(12) .fontColor(#6B6B6B) Text(this.title) .fontSize(11) .fontColor(#666666) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .justifyContent(FlexAlign.Center) } }这个层级适合小尺寸用户第一眼看到天数再确认单位最后识别事项。标题限制一行并使用省略避免长文本把数字挤出卡片。2x2 不适合展示备注、品牌、副标题、按钮和多个事项。小卡片的目标不是信息完整而是“一眼读懂一个值”。七、2x4横向分栏左内容右数字2x4 使用RowRow() { Column() { Text(this.title) .fontSize(14) .fontWeight(FontWeight.Medium) .maxLines(1) Text(this.subtitle) .fontSize(11) .margin({ top: 4 }) .maxLines(1) } .layoutWeight(1) Column() { Text(this.days) .fontSize(40) .fontWeight(FontWeight.Bold) Text(天) .fontSize(12) } }左侧layoutWeight(1)吸收剩余宽度右侧数字保持强视觉。相比写死左侧宽度这种布局更能适应不同字体和系统缩放。标题和副标题虽然都限制一行但源码没有为标题设置textOverflow。长标题可能在不同桌面网格下截断不一致建议补上省略策略并给右侧数字加constraintSize防止极大天数挤压左栏。八、4x4增加品牌和操作暗示4x4 的信息层级最完整Column() { Row() { Text(this.title) .fontSize(16) .fontWeight(FontWeight.Bold) .layoutWeight(1) Text(时光清单) .fontSize(10) } Blank() Row() { Text(this.days) .fontSize(56) .fontWeight(FontWeight.Bold) Text( 天) .fontSize(18) } Text(this.subtitle) .fontSize(13) .maxLines(2) Blank() Text(点击查看详情 ) .fontSize(11) }两个Blank()把标题、核心数字、说明和底部操作暗示分散到纵向空间避免内容都堆在顶部。但这里存在真实的一致性问题源码显示“点击查看详情 ”页面本身没有绑定点击事件CountdownFormAbility.onFormEvent()也只写日志。因此这段文案当前是不可兑现的交互承诺。修复有两种方向接入 Form 支持的点击事件与应用跳转再保留文案。暂不支持点击时删除操作暗示换成纯状态文案。不能只因为视觉上像按钮就让用户以为一定可点击。九、三种尺寸不是缩放而是信息裁剪可以把当前设计整理成一张优先级表信息2x22x44x4天数强强最强单位是是是标题一行、小字号一行一行、较强备注否一行两行品牌否否是点击暗示否否当前有文案但无事件这种“按尺寸裁剪”的方式比统一缩放更符合多尺寸设计。新增字段时先判断它属于哪一级信息再决定从哪个尺寸开始展示。十、配置文件把尺寸和页面一一绑定form_config.json注册三个表单{ forms: [ { name: CountdownSmall, src: ./ets/forms/pages/CountdownCard2x2.ets, uiSyntax: arkts, colorMode: auto, supportDimensions: [2*2], defaultDimension: 2*2, updateEnabled: true, scheduledUpdateTime: 06:00, updateDuration: 1 } ] }中、大尺寸分别绑定CountdownCard2x4.ets和CountdownCard4x4.ets。每个表单只声明一个支持尺寸因此系统选择尺寸时不会让同一个页面被强行拉伸到完全不同的结构。配置中colorMode为auto三个页面却都硬编码#FFFFFF背景和固定灰色文字。系统切换深色模式时卡片仍可能保持白底或与桌面主题显得割裂。若要真正支持 auto应使用可适配资源或明确的深浅色分支如果产品决定固定浅色也要验证系统深色桌面上的边界和对比度。十一、更新链路统一回到 getFormData系统请求更新时onUpdateForm(formId: string): void { hilog.info( 0x0000, TAG, onUpdateForm: ${formId} ); const data formBindingData.createFormBindingData( this.getFormData() ); formProvider.updateForm( formId, data ).catch((err: Error) { hilog.error( 0x0000, TAG, updateForm error: ${err.message} ); }); }添加与更新都调用getFormData()保证选择逻辑、天数算法和空态一致。formId当前只用于更新目标卡片没有参与数据选择因此所有实例会拿到同一选中事项。配置声明每天 06:00 更新同时开启周期更新字段。具体调度频率、最小周期和设备策略应以目标 HarmonyOS SDK 的 Form Kit 文档及真机表现为准不能把配置时间理解成绝对准点保证。系统可能基于资源和策略调整执行。应用内修改纪念日后如需立即刷新桌面卡片还应在保存成功后请求对应 Form 更新而不是只等下一次系统调度。十二、空数据与异常降级没有事项或读取异常时真实能力层返回const fd: FormData { title: 时光清单, days: 0, subtitle: 添加事项开始倒计时, updateTime: Date.now().toString() };这个降级不会让卡片白屏但days: 0可能被误解成“今天就是某个日子”。更明确的设计可以增加statetype FormState content | empty | error; interface FormDataV3 { state: FormState; title: string; days: string; subtitle: string; updateTime: string; }空态时 2x2 可以显示加号或“添加”2x4/4x4 展示引导文案错误态使用“暂时无法读取”避免把系统故障伪装成零天。异常日志当前使用JSON.stringify(e)。生产环境应避免把私密标题或完整业务对象写入日志只记录错误类型和必要诊断码。十三、点击事件与路由契约onFormEvent()当前只是onFormEvent( formId: string, message: string ): void { hilog.info( 0x0000, TAG, onFormEvent: ${formId}, msg: ${message} ); }若要支持“点击查看详情”应让卡片发送窄消息例如interface FormActionMessage { version: 1; action: open_detail; anniversaryId: string; }能力层解析后只把实体 ID交给应用路由应用重新查询最新记录。记录已删除时回退列表。不要把完整实体 JSON 永久写进卡片事件因为桌面卡片可能在数据更新后仍保留旧快照。多实例时消息还应包含或结合formId确认点击的是哪一张卡片。十四、长文本与极值适配需要主动测试这些内容1 个汉字标题。30 个汉字标题。中英数字混合且没有自然断点。空备注与两行长备注。天数为 0、9、99、999、9999。系统字体放大。2x2 的36fp和 4x4 的56fp在四位数时可能过宽。可以动态分级function daysFontSize( days: string, large: boolean ): number { const length days.length; if (large) { if (length 5) return 36; if (length 4) return 44; return 56; } if (length 4) return 28; return 36; }动态字号应按数字长度或容器约束计算不依赖屏幕宽度。目标是让核心数字始终在卡片内部而不是追求所有状态同字号。十五、性能边界卡片回调只做必要工作getFormData()当前读取一个小型 Preferences 数组、排序并选一项成本可控。仍应遵守不在回调中访问网络。不加载大图或解码媒体。不扫描无关数据键。不执行复杂迁移。异常快速返回降级数据。updateTime每次变化会让绑定数据具有新值但不要把它渲染到 UI也不要用高频更新追求秒级倒计时。这个卡片的业务单位是“天”每日或数据变化时更新即可能耗和用户价值更匹配。十六、真机验证矩阵配置和布局必须在真实桌面卡片环境验证三种表单都能在卡片选择器中出现名称和描述正确。2x2、2x4、4x4 添加后分别加载对应页面。空数据时不白屏、不误导为真实“0天”事项。有选中 ID时展示选中事项。选中事项删除后回退排序第一项。未来日期和过去日期的方向文案正确。当天日期显示符合产品定义。长标题、长备注和四位天数不溢出。系统字体放大后核心数字和标题仍可读。浅色与深色桌面下背景、文字、边界对比清楚。06:00 计划更新在真机上实际触发记录执行时间。应用内修改事项后主动刷新路径生效。添加两张卡片时确认是否应共享同一事项。若实现点击冷启动和热启动都进入正确详情。删除桌面卡片后清理按formId保存的选择状态。当前模块只声明phone因此这里验证的是手机桌面卡片。没有经过平板或其他设备注册与材料验证前不应宣称已完成那些设备适配。十七、常见故障与排查顺序现象常见原因修复方向三种尺寸内容不一致各页面自行读数据统一由 FormAbility 生成 FormData添加后显示默认值同步仓库未初始化在回调中完成同步轻量读取删除选中事项后白屏没有回退项selected ?? items[0]过去日期只显示数字使用Math.abs()丢方向增加 direction 与 label4x4 写着可点击但没反应没有事件绑定接入 Form 事件或删除提示深色桌面仍是突兀白卡auto 配合硬编码白色使用主题资源或明确固定模式两张卡片总显示同一事项选择 ID为全局单值按 formId 保存映射天数变了但卡片没刷新只依赖计划更新数据保存后请求更新 Form四位天数挤出容器字号固定按长度分级并加约束排查时按“配置是否注册、能力层是否生成数据、绑定键是否匹配、页面是否渲染、系统是否更新”五层进行。不要一开始就修改字号因为很多“显示默认值”其实是数据绑定或仓库初始化问题。十八、历史问题复盘选择状态为什么必须成为数据契约历史错误记录提供了一个很有价值的边界应用内预览选中了某个纪念日不等于桌面 Form 自动知道这个选择。应用页面、桌面卡片和 FormExtensionAbility 处在不同的界面与生命周期中只有把选择写入双方都能读取的持久化键能力层才能在添加或更新卡片时恢复同一个业务对象。当前WidgetView会加载纪念日列表读取WIDGET_ANNIVERSARY_ID没有已有选择时它会把第一条记录的 ID 写进去。用户在列表中切换事项时也会更新这个全局键。AddView在第一次保存记录且尚无选择时同样会把新记录 ID 写为默认选择。CountdownFormAbility再读取这个键从仓库结果中查找对应记录。这里可以确认的是静态数据链已经闭合不能仅凭代码断言跨进程可见性、写入时序和桌面刷新时机已经在本文环境中验证。这段历史也说明组件预览与真实 Form 必须分开验收。WidgetView中的小、中、大预览由应用页面自己的 Builder 和主题令牌绘制真正的桌面内容由三个forms/pages页面绘制。预览正确只能证明应用内布局状态合理不能替代系统桌面上的 Form 加载、数据绑定和更新测试。建议为这条链路建立一份窄而明确的存储契约而不是让页面随意拼接键名// 建议实现当前源码仍使用单个全局键。 export interface WidgetSelectionSnapshot { version: 1; globalSelectedId: string; selectedByFormId: Recordstring, string; updatedAt: number; }version用于将来迁移globalSelectedId可保留为旧数据或默认值selectedByFormId才承担多实例差异。迁移时先读取旧键再在用户真正为某个实例做选择时写入映射避免升级后突然清空已有选择。十九、建议把“数字”升级成可判定的业务状态当前能力层对calcDaysRemaining()使用Math.abs()因此它输出的是距离绝对值而不是完整倒计时语义。对视觉稿来说数字3很干净对用户来说“还有 3 天”和“已经过去 3 天”完全不同。当天、空数据和读取失败也不应都借用数字0表达。建议先在能力层构造离散状态再让不同尺寸决定展示多少字段// 建议实现不是当前 FormData 的真实定义。 type CountdownState future | today | past | empty | error; interface CountdownFormSnapshot { state: CountdownState; title: string; days: string; directionLabel: string; subtitle: string; anniversaryId: string; updatedAt: string; }2x2 可以在future和past状态下仍突出绝对天数但至少用“还剩”“已过”或颜色、图标之一提供方向today应显示“今天”而不是模糊的0empty应引导添加事项error应说明暂时无法读取。2x4 可以增加一行方向或备注4x4 再展示更完整说明。这样三种尺寸共用同一语义不会由三个页面各自猜测业务状态。状态转换函数也应保持纯净便于单元测试边界日期// 建议实现rawDays 的正负含义必须与项目日期工具保持一致。 function resolveCountdownState(rawDays: number): CountdownState { if (rawDays 0) return today; return rawDays 0 ? future : past; }这里特别要避免直接照抄正负判断。实施前应先用项目当前calcDaysRemaining()对“昨天、今天、明天”各跑一个固定样例确认正数究竟代表未来还是过去再写断言。本文只能确认调用处用了绝对值不能在未运行样例时把方向规则当成已证实事实。二十、多实例不是换一个键名而是完整生命周期如果产品只允许所有桌面卡片共享同一个事项当前全局选择 ID 已经足够界面还应明确告诉用户“所有卡片同步”。如果希望两张卡片分别显示生日和纪念日就需要让formId进入选择、更新、点击和删除四条链路。建议的读取优先级是“实例选择、全局默认、排序第一项、空态”。伪代码如下// 建议实现。 const selectedId selectedByFormId[formId] ?? globalSelectedId; const selected items.find((item) item.id selectedId); const target selected ?? items[0];写入时要知道用户正在配置哪一个formId更新时只刷新受影响实例或者在数据变化影响多个实例时枚举对应卡片删除时在onRemoveForm(formId)清理映射。若被选事项已删除不要只删除选择键还应按既定降级规则生成下一帧数据。否则同一问题会以“卡片突然回默认值”的形式再次出现。多实例还会影响隐私与日志。日志可以记录formId的脱敏片段、状态枚举和错误码但不应输出纪念日标题、备注或完整持久化快照。调试便利不能成为长期暴露用户内容的理由。二十一、点击与主动更新必须用真实闭环验收当前 4x4 页面展示“点击查看详情”但所检查页面没有看到对应动作绑定能力层onFormEvent()也只记录日志。建议先定义窄动作再接入目标 SDK 支持的 Form 交互 API。消息只携带动作、版本和实体 ID详情页启动后重新从仓库查询最新数据// 建议契约具体动作绑定 API 以目标 SDK 官方文档为准。 interface OpenDetailAction { version: 1; action: open_detail; anniversaryId: string; formId: string; }验收时至少覆盖冷启动、热启动、记录已删除、ID 非法、重复点击和返回桌面。只有文字、动作绑定、能力回调和应用路由都走通才可以保留“点击查看详情”。在此之前删除这句提示比留下无法兑现的操作更诚实。更新也应区分两类触发。计划更新用于跨天后刷新天数数据变更更新用于新增、编辑、删除、置顶或切换选择后尽快同步。form_config.json中出现scheduledUpdateTime、updateDuration与updateEnabled只能证明配置字段存在是否按预期触发、触发精度以及系统资源策略需要目标设备记录实际回调时间。建议的数据变更路径是仓库写入确认成功计算受影响的卡片实例请求更新更新失败时保留持久化结果并记录可诊断错误。不能在持久化尚未确认时先刷新卡片否则内存、磁盘与桌面可能短暂分叉。也不能因为updateTime每次变化就宣称系统一定会主动拉取新数据它只是当前绑定数据中的一个变化字段。二十二、把验收结果分级避免一次通过代表全部通过这类功能适合把证据分成五级。第一级是静态源码注册项、页面路径、字段名和降级逻辑存在。第二级是本地构建目标命令真实执行并通过。第三级是设备运行安装、添加三种尺寸、更新、空态、长文本和深浅色实际可见。第四级是生命周期跨天、重启、删除事项、删除卡片、多实例、冷启动点击都成立。第五级才是发布侧证据包体、材料、审核与线上状态。本文当前只完成第一级复核并引用了一条明确标注日期的历史构建记录。下列结果都没有在本文环境中重新获得因此不写成完成当前构建成功、真机添加成功、06:00 准点触发、点击详情成功、多实例独立选择成功、发布审核通过、用户使用量或平台评分。建议后续每次验证都保留“命令或动作、时间、设备或环境、预期、实际、日志证据”六项。比如计划更新不要只写“等到第二天看看”而应记录卡片添加时间、设备电量与网络状态、预期窗口、onUpdateForm实际日志时间和渲染结果。这样遇到系统调度偏差时才能判断是配置、系统策略、进程状态还是数据生成问题。当以上证据逐层补齐后再把建议代码转成当前事实。这个顺序虽然比直接宣布“已适配”更慢却能让文章、源码和真实设备始终保持一致。总结时光清单的倒计时 Form 已经建立了可迁移的多尺寸骨架三种尺寸各自拥有独立 ArkTS 页面统一通过FormData接收同一仓库结果添加与更新复用同一数据生成函数空数据也有降级内容。多尺寸适配的核心不是三份相似代码而是两条稳定边界数据语义只定义一次信息密度按尺寸递增。接下来应补齐方向标签、按实例选择、主动更新、深浅色资源和真实点击事件。把这些边界验证清楚后2x2、2x4 与 4x4 才不是三个静态截图而是同一业务在不同桌面面积上的一致表达。AI 辅助声明本文由 AI 辅助整理结论与代码路径基于D:\huawei\one8中CountdownCard.ets、三个 Form 页面、CountdownFormAbility.ets、仓库和form_config.json的真实源码复核扩展模型与交互方案需结合目标 HarmonyOS SDK 和真机测试后采用。
返回列表