HarmonyOS 互动卡片(Live Form)入门指南:双态架构与场景动效全景解析

前言

服务卡片(Service Card)是 HarmonyOS 的标志性特性之一,能够将应用的核心信息以卡片形式展示在桌面,让用户无需打开应用即可获取关键信息。然而,传统的动态卡片本质上是一张"图"——UI 被钉在卡片的矩形框里,动画能力有限,也无法接入传感器。

HarmonyOS 推出的互动卡片(Live Form,场景动效类型互动卡片)彻底打破了这一限制。它支持帧动画、3D 变换、陀螺仪交互,甚至能将渲染区域扩展到卡片边界之外,营造"破框"效果。用户点击卡片或摇一摇手机,憨憨(官方吉祥物角色)就会在卡片上"活"起来——起床、跑步、取快递、跳舞。

本文作为互动卡片系列的第一篇,将从概念原理、双态架构、四种卡片类型、API 全景到前置条件,带你系统地理解这项能力。

一、互动卡片概念解析

1.1 什么是互动卡片

互动卡片(场景动效类型互动卡片)是一种支持动态动画和实时交互的卡片形态,区别于传统动态卡片,它具有以下核心能力:

能力 传统动态卡片 互动卡片
帧动画 不支持 支持流畅帧动画
3D 变换 不支持 支持缩放、旋转、透视
传感器交互 不支持 支持陀螺仪等传感器
破框渲染 不支持 渲染区域可超出卡片边界
摇一摇触发 不支持 支持(需要 HarmonyOS 7.0+)

1.2 双态架构设计

互动卡片采用双态管理架构,同一张卡片在不同状态下由不同的 Ability 管理:

在这里插入图片描述

图:互动卡片双态架构——非激活态(左)与激活态(右)由不同的 Ability 管理

状态 管理 Ability 渲染方式 交互能力
非激活态 FormExtensionAbility ArkTS 声明式 UI 有限点击、数据刷新
激活态 LiveFormExtensionAbility 动态 UI 页面 帧动画、陀螺仪、破框渲染

核心设计:同一张卡片,平时是 FormExtensionAbility 管的普通卡片,触发后换成 LiveFormExtensionAbility 管的动态 UI。两者靠 form_config.json 里的 sceneAnimationParams 串起来。

1.3 互动卡片类型

互动卡片包含两种类型,本文仅介绍场景动效类型

类型 说明 触发方式
趣味交互类型 通过 funInteractionParams 配置 点击
场景动效类型 通过 sceneAnimationParams 配置 点击、摇一摇

二、四种官方示例卡片全景

2.1 卡片总览

官方提供了四种互动卡片示例,分别对应不同的交互场景和体验效果:

卡片名称 用途 触发方式 核心技术
睡眠卡片 状态提醒、起床动效 点击 帧动画、状态切换、破框
快递卡片 快递物流状态 点击 + 摇一摇 帧动画、陀螺仪交互
运动卡片 运动记录、卡路里计数 点击 帧动画、数字累加
音乐卡片 音乐播放控制 点击 Canvas 自绘制、音频控制

2.2 睡眠卡片

触发方式:点击。

体验及交互:点击卡片触发憨憨起床动画,三叶草旋转,气球飘出卡片边界,憨憨从睡姿变为醒姿,动画结束后卡片状态更新为"按时起床"。

2.3 快递卡片

触发方式:点击、摇一摇。

体验及交互:点击卡片或摇动设备激活卡片后,倾斜手机驱动憨憨沿路线跑动——向右倾斜憨憨向右移动并缩小(近→远透视),向左倾斜憨憨向左移动并放大(远→近透视)。

2.4 运动卡片

触发方式:点击。

体验及交互:点击"开始运动"触发拉伸运动动画;点击"结束运动"触发庆祝动画并显示卡路里计数,从 0 逐步增长到 300kcal。

2.5 音乐卡片

触发方式:点击。

体验及交互:播放音乐时憨憨跳舞、专辑封面旋转;切歌时憨憨出框取专辑进行替换。

三、核心 API 全景

3.1 关键接口一览

接口名 所属模块 描述
onLiveFormCreate(liveFormInfo, session) LiveFormExtensionAbility 互动卡片界面对象创建的回调
onLiveFormDestroy(liveFormInfo) LiveFormExtensionAbility 互动卡片界面对象销毁的回调
formProvider.requestOverflow(formId, overflowInfo) @kit.FormKit 卡片提供方发起互动卡片动效请求
formProvider.cancelOverflow(formId) @kit.FormKit 卡片提供方取消互动卡片动效
formProvider.getFormRect(formId) @kit.FormKit 查询卡片位置、尺寸
formProvider.updateForm(formId, formBindingData) @kit.FormKit 更新卡片数据
postCardAction(ROUTER) @kit.FormKit 卡片跳转到应用页面
postCardAction(MESSAGE) @kit.FormKit 卡片发送消息到 FormExtensionAbility
postCardAction(CALL) @kit.FormKit 卡片调用应用方法
startAbilityByLiveForm(want) LiveFormExtensionContext 互动卡片拉起应用页面

3.2 LiveFormInfo 关键字段

字段 类型 说明
formId string 卡片唯一标识
borderRadius number 卡片圆角信息
rect formInfo.Rect 非激活态卡片相对激活态 UI 的位置和尺寸

3.3 OverflowInfo 关键字段

字段 类型 说明
area { left, top, width, height } 破框区域
duration number 动画时长(毫秒)

四、前置条件与环境准备

4.1 版本要求

组件 最低版本 说明
开发工具 DevEco Studio 6.1.0 Release 互动卡片开发环境
HarmonyOS SDK 6.1.0+ 基础能力
摇一摇触发 HarmonyOS 7.0+ 摇一摇依赖系统级 shake 事件
语言 ArkTS 统一使用 V2 装饰器

4.2 前置知识

在阅读本文之前,建议先了解以下基础知识:

  1. HarmonyOS 卡片开发基础
  2. ArkTS 语法
  3. UIAbility 生命周期
  4. FormExtensionAbility 开发

4.3 设备要求

  • 支持实况窗的真机或模拟器
  • 部分模拟器可能不支持摇一摇(shake),建议真机验证陀螺仪效果
  • 摇一摇功能需 HarmonyOS 7.0 及以上版本

五、整体架构与数据流

5.1 整体架构

互动卡片以动态卡片作为入口,通过 form_config.json 中的 sceneAnimationParams 配置关联 LiveFormExtensionAbility。用户触发激活后,系统根据 sceneAnimationParams.abilityName 激活对应的 LiveFormExtensionAbility 实例:


### 6.7 摇一摇触发处理(onUpdateForm)

当用户在 `triggerTypes` 中配置了 `"shake"` 时,摇一摇事件会触发 `FormExtensionAbility.onUpdateForm`:

```typescript
// 在 FormExtensionAbility 中处理摇一摇事件
async onUpdateForm(formId: string): Promise<void> {
  console.info(`摇一摇触发,激活卡片: ${formId}`);
  // 摇一摇触发时,主动调用 requestOverflow 激活互动卡片
  await this.requestOverflow(formId, 1.0, 1.0, 5000);
}

6.8 卡片尺寸适配(获取 formRect)

import { formProvider, formInfo } from '@kit.FormKit';

/**
 * 获取卡片当前尺寸信息
 * 用于计算破框区域和适配不同尺寸的卡片
 */
async function getCardDimensions(formId: string): Promise<formInfo.Rect | null> {
  try {
    const formRect = await formProvider.getFormRect(formId);
    console.info(`卡片尺寸: ${formRect.width}x${formRect.height}`);
    return formRect;
  } catch (err) {
    console.error(`获取卡片尺寸失败: ${JSON.stringify(err)}`);
    return null;
  }
}

用户触发(点击/摇一摇)

系统识别触发事件

查找 sceneAnimationParams.triggerTypes 配置的卡片

读取 sceneAnimationParams.abilityName

调用 FormExtensionAbility.onFormEvent(MESSAGE 路径)

formProvider.requestOverflow 激活互动卡片

创建 LiveFormExtensionAbility 实例

onLiveFormCreate → session.loadContent 加载动画 UI


### 5.2 两种触发路径

| 触发方式 | 发起方 | 流程 | 最低版本 |
|---------|--------|------|---------|
| 点击触发 | 卡片自身 | 卡片 → `postCardAction(MESSAGE)` → `FormExtensionAbility.onFormEvent` → `requestOverflow` | API 12+ |
| 摇一摇触发 | 系统 | 系统检测 shake → 查找 triggerTypes 含 "shake" 的卡片 → `FormExtensionAbility.onUpdateForm` → `requestOverflow` | HarmonyOS 7.0+ |

## 六、基础代码入门

### 6.1 动态卡片创建(入口)

动态卡片是互动卡片的入口,需按标准流程创建:

```typescript
// entry/src/main/ets/widget/pages/DeliveryCard.ets
import { ActionUtils } from '../../utils/ActionUtils';
import { LiveCardScale } from '../../constants/LiveCardConstants';

const LIVE_CARD_DURATION: number = 5000;

@Entry
@Component
struct DeliveryCard {
  build() {
    RelativeContainer() {
      // 背景图片
      Image($rawfile('delivery/background.png'))
        .objectFit(ImageFit.Contain)
        .width('100%')
        .height('100%')
        .aspectRatio(1);

      // 憨憨角色图片
      Image($rawfile('delivery/fuzzball.png'))
        .objectFit(ImageFit.Contain)
        .width('145%')
        .height('145%')
        .offset({ x: `-22.5%`, y: `-22.5%` });

      // 文字说明
      Image($rawfile('delivery/delivery_text.png'))
        .objectFit(ImageFit.Contain)
        .width('100%')
        .height('100%')
        .aspectRatio(1);

      // 底部跳转区域
      Stack()
        .width('100%')
        .height('30%')
        .onClick(() => {
          ActionUtils.jumpAppPage(this, 'DeliveryPage');
        })
        .alignRules({
          left: { anchor: '__container__', align: HorizontalAlign.Start },
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
        });
    }
    .width('100%')
    .height('100%')
    .onClick(() => {
      // 点击触发互动卡片激活
      ActionUtils.requestOverFlow(
        this, LiveCardScale.DELIVERY_WIDTH,
        LiveCardScale.DELIVERY_HEIGHT, LIVE_CARD_DURATION
      );
    });
  }
}

6.2 form_config.json 配置

{
  "forms": [
    {
      "name": "DeliveryCard",
      "displayName": "$string:DeliveryCard",
      "description": "$string:DeliveryCardDes",
      "src": "./ets/widget/pages/DeliveryCard.ets",
      "uiSyntax": "arkts",
      "isDynamic": true,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"],
      "sceneAnimationParams": {
        "abilityName": "DeliveryLiveCardAbility",
        "triggerTypes": ["shake"]
      }
    }
  ]
}

6.3 module.json5 声明

{
  "module": {
    "extensionAbilities": [
      {
        "name": "EntryFormAbility",
        "srcEntry": "./ets/entryformability/EntryFormAbility.ets",
        "type": "form",
        "metadata": [
          {
            "name": "ohos.extension.form",
            "resource": "$profile:form_config"
          }
        ]
      },
      {
        "name": "DeliveryLiveCardAbility",
        "srcEntry": "./ets/livecardability/DeliveryLiveCardAbility.ets",
        "type": "liveForm"
      }
    ]
  }
}

6.4 LiveFormExtensionAbility 实现

// entry/src/main/ets/livecardability/DeliveryLiveCardAbility.ets
import { LiveFormExtensionAbility, LiveFormInfo, formInfo } from '@kit.FormKit';
import { UIExtensionContentSession } from '@kit.AbilityKit';

export default class DeliveryLiveCardAbility extends LiveFormExtensionAbility {
  onLiveFormCreate(liveFormInfo: LiveFormInfo, session: UIExtensionContentSession): void {
    const storage: LocalStorage = new LocalStorage();

    // 传递上下文
    storage.setOrCreate('context', this.context);
    storage.setOrCreate('session', session);

    // 传递卡片信息
    const formId: string = liveFormInfo.formId;
    storage.setOrCreate('formId', formId);

    // 传递圆角信息
    const borderRadius: number = liveFormInfo.borderRadius;
    storage.setOrCreate('borderRadius', borderRadius);

    // 传递卡片位置和尺寸
    const formRect: formInfo.Rect = liveFormInfo.rect;
    storage.setOrCreate('formRect', formRect);

    try {
      // 加载互动卡片 UI 页面
      session.loadContent('livecardability/pages/DeliveryLiveCard', storage);
    } catch (error) {
      console.error(`session.loadContent error: ${JSON.stringify(error)}`);
    }
  }

  onLiveFormDestroy(liveFormInfo: LiveFormInfo): void {
    console.info(`LiveForm destroyed: ${liveFormInfo.formId}`);
  }
}

6.5 激活动效请求(requestOverflow)

// 在 FormExtensionAbility 中处理激活动效请求
async onFormEvent(formId: string, message: string): Promise<void> {
  const params: Record<string, Object> = JSON.parse(message);
  const shortMessage: string = params.message as string;

  if (shortMessage === 'requestOverflow') {
    const widthRatio: number = params.widthRatio as number;
    const heightRatio: number = params.heightRatio as number;
    const duration: number = params.duration as number;
    await this.requestOverflow(formId, widthRatio, heightRatio, duration);
  }
}

private async requestOverflow(
  formId: string, widthRatio: number, heightRatio: number, duration: number
): Promise<void> {
  try {
    const formRect: formInfo.Rect = await formProvider.getFormRect(formId);
    if (formRect.width <= 0 || formRect.height <= 0) return;

    const cardWidth = formRect.width * widthRatio;
    const cardHeight = formRect.height * heightRatio;
    const leftOffset = (formRect.width - cardWidth) / 2;
    const topOffset = (formRect.height - cardHeight) / 2;

    await formProvider.requestOverflow(formId, {
      area: {
        left: leftOffset,
        top: topOffset,
        width: cardWidth,
        height: cardHeight
      },
      duration: duration
    });
  } catch (err) {
    console.error(`requestOverflow error: ${JSON.stringify(err)}`);
  }
}

6.6 取消动效(cancelOverflow)

// 在互动卡片 UI 中点击取消动效
.onClick(() => {
  formProvider.cancelOverflow(this.formId).catch((err: BusinessError) => {
    console.error(`cancelOverflow error: ${err.code}, ${err.message}`);
  });
})

七、约束与限制

限制项 说明
开发工具 DevEco Studio 6.1.0 Release 及以上
摇一摇触发 HarmonyOS 7.0 及以上版本
设备类型 支持实况窗的真机或模拟器
状态管理 建议统一使用 V2 装饰器(@ComponentV2@Local@LocalStorageProp
五元组 卡片五元组(bundleName、moduleName、abilityName、formName、formDimension)变更会导致卡片被删除

八、总结

本文作为互动卡片系列入门篇,系统介绍了以下核心内容:

  • 概念原理:互动卡片是支持帧动画、3D 变换、陀螺仪交互和破框渲染的高级卡片形态
  • 双态架构:非激活态由 FormExtensionAbility 管理,激活态由 LiveFormExtensionAbility 管理
  • 四种卡片:睡眠卡片(起床动画)、快递卡片(陀螺仪交互)、运动卡片(卡路里累加)、音乐卡片(Canvas 自绘制)
  • API 全景:10 个核心接口,覆盖卡片创建、激活、取消、数据推送
  • 基础代码:动态卡片 UI、配置文件、LiveFormExtensionAbility、requestOverflow

下一篇将深入讲解互动卡片的配置与触发机制,包括 form_config.json 详解、module.json5 配置、点击触发与摇一摇触发的完整流程。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

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

更多推荐