Harmony os 静态卡片开发(ArkTS + FormLink)

59 阅读4分钟

静态卡片(ArkTS + FormLink)

1. 概述

鸿蒙第四期活动 在 HarmonyOS 中,服务卡片分为 动态卡片静态卡片

  • 动态卡片:支持在运行时通过 postCardAction() 交互。
  • 静态卡片:不能 调用 postCardAction(),而是通过 FormLink 组件 与应用交互。

ArkTS 卡片提供 FormLink 静态卡片交互组件,用于静态卡片内部与卡片提供方应用之间的交互。 FormLink 支持三种事件类型:

  • router:页面跳转(拉起 UIAbility)
  • message:向 FormExtensionAbility 发送消息
  • call:后台拉起 UIAbility 执行指定方法

静态卡片的典型结构由三部分组成:

  1. EntryFormAbility.ets:卡片生命周期管理(创建、更新、事件回调)。
  2. WidgetCard.ets:卡片 UI 页面(ArkTS 编写)。
  3. form_config.json:卡片配置信息(尺寸、布局、是否静态卡片等)。

2. 创建 ArkTS 静态卡片工程

在 DevEco Studio 中:

  1. 右键工程 → New → ArkTS Card(或 Module → Service Widget)
  2. 选择使用 ArkTS 语法,填写卡片名称等基本信息。
  3. 创建完成后,工程会自动生成以下文件:
  • EntryFormAbility.ets

    • 继承 FormExtensionAbility
    • 负责卡片的创建 onAddForm、删除 onRemoveForm、更新 onUpdateForm、处理事件 onFormEvent 等。
  • WidgetCard.ets

    • ArkTS UI 页面文件
    • 使用 @Entry @Component 定义卡片 UI。
  • form_config.json

    • 描述卡片的尺寸、布局文件路径、是否为静态卡片等。
    • 比如卡片大小、卡片 ID、默认卡片等配置都在这里。

创建向导里的默认 UI 只是示例,实际开发中我们通常会删掉默认 UI,自定义 UI 和交互逻辑


3. 配置 ArkTS 卡片的配置文件(form_config.json 概念)

这里只给重要字段的含义思路(不用死记 JSON):

  • name:卡片名称,对外展示。
  • description:卡片描述。
  • type:一般为 "JS"(ArkTS 卡片也属于此类)。
  • uiSyntax:ArkTS 卡片一般为 "arkts"
  • isStatic:是否静态卡片。静态卡片必须为 true
  • src:指向 WidgetCard.ets 对应的 UI 路径。
  • supportDimensions:支持的卡片规格(例如 ["2*2"])。
  • defaultDimension:默认尺寸。

配置完成后记得点击 Finish / OK,触发构建,让卡片配置生效。


4. WidgetCard:自定义静态卡片 UI

新建 ArkTS 卡片后,WidgetCard.ets 会自带一段默认 UI。 实际开发中我们常常会:

  1. 删除默认 UI 代码;
  2. 自己用 Column/Row/Stack/Text/Image 等组件重写。

例如,我们清空默认内容后,可以这样写一个最简单的静态卡片:

 @Entry
 @Component
 struct WidgetCard {
   build() {
     Column() {
       Text('Hello Static Widget')
         .fontSize(20)
         .fontWeight(FontWeight.Medium)
         .fontColor('#333333')
         .margin(12)
     }
     .width('100%')
     .height('100%')
   }
 }

5. 卡片背景设置(推荐做法)

⚠ 在 卡片(WidgetCard) 中,不能直接使用 .backgroundImage() 来设置背景图。 原因:卡片是一个轻量独立模块,不支持部分常规页面装饰能力。

正确方式:使用 Image + Stack 实现背景效果。

5.1 资源准备

  1. 将图片放到: resources/base/media/ 目录下 例如:resources/base/media/background.png

  2. resources/base/profile/media.json 中注册对应的资源 ID(DevEco 一般会自动生成)。

  3. 命名规范:

    • background.png
    • card_bg.jpg
    • BackGround.png(大写 / 奇怪字符不推荐)

5.2 背景 + 前景内容示例

 @Entry
 @Component
 struct WidgetCard {
   title: string = 'Keep Running'
 ​
   build() {
     Column() {
       Stack() {
         // 1. 背景图
         Image($r('app.media.background')) // 注意要和 media.json 中的 name 一致
           .width('100%')
           .height('100%')
           .objectFit(ImageFit.Cover)      // 填满卡片区域
 ​
         // 2. 前景内容
         Column() {
           Text(this.title)
             .fontColor('#c6ea96d6')
             .fontWeight(FontWeight.Bold)
             .fontSize(20)
             .margin({ left: 12, top: 12 })
         }
       }
     }
     .width('100%')
     .height('100%')
   }
 }

Stack 的作用

  • 最底层放背景 Image
  • 上面叠加 Column/Row/Text 等前景内容

6. 使用 FormLink 实现静态卡片交互

静态卡片不能用 onClick 直接调逻辑,而是通过 FormLink 包裹可点击区域。

6.1 router 事件:点击卡片打开应用页面

下面是一个「点击卡片跳转到应用详情页」的完整示例:

 @Entry
 @Component
 struct WidgetCard {
   title: string = '今日学习打卡'
 ​
   build() {
     // 整个卡片区域都可点击
     FormLink({
       action: 'router',              // 跳转类型
       abilityName: 'EntryAbility',   // 目标 UIAbility
       // 可选:bundleName / moduleName,通常省略,默认当前应用
       params: {
         targetPage: 'studyDetail',   // 约定的目标页面标识
         from: 'staticWidget'
       }
     }) {
       // 内部是卡片 UI 内容
       Stack() {
         Image($r('app.media.background'))
           .width('100%')
           .height('100%')
           .objectFit(ImageFit.Cover)
 ​
         Column() {
           Text(this.title)
             .fontColor('#FFFFFF')
             .fontWeight(FontWeight.Bold)
             .fontSize(20)
             .margin({ left: 12, top: 12 })
 ​
           Text('点击查看详细学习统计')
             .fontColor('#FFFFFF')
             .opacity(0.8)
             .fontSize(14)
             .margin({ left: 12, top: 6 })
         }
       }
     }
   }
 }

UIAbility 中解析参数决定跳转页面(简单示意):

 // EntryAbility.ts 片段
 import UIAbility from '@ohos.app.ability.UIAbility';
 import type Want from '@ohos.app.ability.Want';
 import window from '@ohos.window';
 ​
 let targetPage: string = 'pages/Index';
 ​
 export default class EntryAbility extends UIAbility {
   onCreate(want: Want) {
     if (want.parameters && want.parameters.params) {
       try {
         const params = JSON.parse(want.parameters.params as string);
         targetPage = params.targetPage === 'studyDetail'
           ? 'pages/StudyDetail'
           : 'pages/Index';
       } catch (e) {
         console.error('parse params error', e);
       }
     }
   }
 ​
   onWindowStageCreate(windowStage: window.WindowStage) {
     windowStage.loadContent(targetPage);
   }
 }

7. FormLink 的 message / call 简要示例

7.1 message:通知 FormExtensionAbility 刷新卡片

 FormLink({
   action: 'message',
   params: {
     op: 'refresh',
     timestamp: Date.now()
   }
 }) {
   Text('点击刷新卡片内容')
     .fontSize(16)
     .margin(12)
 }

EntryFormAbility.ets 中:

 onFormEvent(formId: string, message: string) {
   // message 是 JSON 字符串
   const payload = JSON.parse(message);
   if (payload.op === 'refresh') {
     // TODO:读取最新数据 → 调用 updateForm 更新卡片
   }
 }

7.2 call:后台拉起 UIAbility 执行任务

 FormLink({
   action: 'call',
   abilityName: 'EntryAbility',
   params: {
     method: 'syncFromCloud',   // UIAbility 内约定的方法名
     extraInfo: 'some data'
   }
 }) {
   Text('后台同步数据')
     .fontSize(16)
     .margin(12)
 }

UIAbility 内在 onCreate/onNewWant 里解析 params.method,根据不同方法名执行不同逻辑(例如:从云端同步数据、更新数据库,然后再通过 formProvider.updateForm 刷新卡片)。


8. 小结(你可以当作复习提纲)

  1. 静态卡片交互入口是 FormLink,支持 router / message / call 三种事件。

  2. 静态卡片相关文件:

    • EntryFormAbility.ets:生命周期 & 事件处理
    • WidgetCard.ets:卡片 UI & FormLink
    • form_config.json:卡片配置(尺寸 / 是否静态 / UI 路径)
  3. 卡片背景不要用 .backgroundImage(),用 Stack + Image 实现。

  4. router:点击卡片跳转应用页面(最常用)。

  5. message:告诉 FormExtensionAbility 做数据刷新,仅改卡片。

  6. call:在后台拉起 UIAbility 执行任务,不切到前台。