HarmonyOS 互动卡片实战进阶:配置详解与双触发机制全链路实践

前言

上一篇文章中,我们系统介绍了互动卡片的概念原理、双态架构和基础 API。但概念终要落地——form_config.json 中的 sceneAnimationParams 如何配置?module.json5 中如何声明 LiveFormExtensionAbility?点击触发和摇一摇触发两条路径的区别是什么?requestOverflow 破框区域如何计算?

本文将从配置文件详解、双 Ability 声明、两种触发机制到破框区域计算,逐一拆解互动卡片的配置与触发全链路。

一、form_config.json 配置详解

1.1 完整配置结构

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": ["click", "shake"]
      }
    }
  ]
}

1.2 关键字段说明

字段 必填 类型 说明
name string 卡片名称,卡片五元组之一
displayName string 卡片显示名称
description string 卡片描述
src string 卡片 UI 页面路径
uiSyntax string UI 语法,固定为 "arkts"
isDynamic boolean 是否为动态卡片,互动卡片必须为 true
defaultDimension string 默认尺寸
supportDimensions string[] 支持的尺寸列表
sceneAnimationParams object 场景动效配置(互动卡片关键字段)

1.3 sceneAnimationParams 详解

字段 必填 类型 说明
abilityName string 激活时启动的 LiveFormExtensionAbility 名称
triggerTypes string[] 触发动画方式,支持 "click""shake"

重要提示sceneAnimationParams.abilityName 必须和 module.json5LiveFormExtensionAbilityname 一字不差,否则触发时系统找不到目标。

1.4 四种卡片的配置差异

卡片 triggerTypes 说明
睡眠卡片 ["click"] 仅点击触发
快递卡片 ["click", "shake"] 点击 + 摇一摇
运动卡片 ["click"] 仅点击触发
音乐卡片 ["click"] 仅点击触发

二、module.json5 双 Ability 声明

2.1 完整配置

{
  "module": {
    "name": "entry",
    "type": "entry",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet"],
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets"
      }
    ],
    "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"
      }
    ]
  }
}

2.2 双 Ability 对比

维度 FormExtensionAbility LiveFormExtensionAbility
type "form" "liveForm"
管理状态 非激活态 激活态
生命周期 onCreateonUpdateFormonDestroy onLiveFormCreateonLiveFormDestroy
渲染能力 静态卡片 UI 动态动画 UI
传感器 不支持 支持陀螺仪等

2.3 配置注意事项

  1. abilityName 必须一致form_config.jsonsceneAnimationParams.abilityName 的字符串必须与 module.json5extensionAbilitiesname 字段完全一致
  2. type 必须正确FormExtensionAbilitytype"form"LiveFormExtensionAbilitytype"liveForm"
  3. metadata 必须配置FormExtensionAbility 需要 metadata 指向 form_config.json

三、点击触发机制详解

3.1 点击触发流程

点击触发是互动卡片最常用的激活方式,完整流程如下:

用户点击卡片
    ↓
卡片 UI 调用 postCardAction(MESSAGE) 发送 "requestOverflow" 消息
    ↓
FormExtensionAbility.onFormEvent 接收消息
    ↓
解析消息参数(widthRatio、heightRatio、duration)
    ↓
调用 formProvider.getFormRect 获取卡片位置尺寸
    ↓
计算破框区域(area)
    ↓
调用 formProvider.requestOverflow 向系统申请破框
    ↓
系统创建 LiveFormExtensionAbility 实例
    ↓
onLiveFormCreate → session.loadContent 加载动画 UI

3.2 点击触发完整代码

// 1. 卡片 UI 中发送消息
// entry/src/main/ets/widget/pages/DeliveryCard.ets
@Entry
@Component
struct DeliveryCard {
  build() {
    RelativeContainer() {
      // 卡片内容...
    }
    .width('100%')
    .height('100%')
    .onClick(() => {
      // 关键:点击时发送 requestOverflow 消息
      ActionUtils.requestOverFlow(
        this,
        LiveCardScale.DELIVERY_WIDTH,   // 宽度比例
        LiveCardScale.DELIVERY_HEIGHT,  // 高度比例
        LIVE_CARD_DURATION              // 动画时长
      );
    });
  }
}

// 2. ActionUtils.requestOverFlow 实现
// entry/src/main/ets/utils/ActionUtils.ets
export class ActionUtils {
  static requestOverFlow(
    component: object,
    widthRatio: number,
    heightRatio: number,
    duration: number
  ): void {
    const params: Record<string, Object> = {
      message: 'requestOverflow',
      widthRatio: widthRatio,
      heightRatio: heightRatio,
      duration: duration
    };
    postCardAction(component, {
      action: 'message',
      message: JSON.stringify(params)
    });
  }

  static jumpAppPage(component: object, pageName: string): void {
    postCardAction(component, {
      action: 'router',
      abilityName: 'EntryAbility',
      params: { targetPage: pageName }
    });
  }
}

// 3. FormExtensionAbility 处理消息
// entry/src/main/ets/entryformability/EntryFormAbility.ets
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 = params.widthRatio as number;
    const heightRatio = params.heightRatio as number;
    const duration = 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 = await formProvider.getFormRect(formId);
    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)}`);
  }
}

四、摇一摇触发机制详解

4.1 摇一摇触发流程

摇一摇触发是 HarmonyOS 7.0 新增的激活方式,流程如下:

步骤 操作 说明
1 用户摇动设备 系统识别摇一摇事件
2 查找 triggerTypes"shake" 的卡片 匹配支持的卡片
3 读取 sceneAnimationParams.abilityName 获取 LiveFormExtensionAbility 名称
4 触发 FormExtensionAbility.onUpdateForm 系统将摇一摇事件发送给卡片
5 调用 requestOverflow 请求激活 FormExtensionAbility 中主动拉起
6 创建 LiveFormExtensionAbility 实例 系统自动创建
7 调用 onLiveFormCreate 方法 加载动画 UI

4.2 摇一摇触发配置

{
  "sceneAnimationParams": {
    "abilityName": "DeliveryLiveCardAbility",
    "triggerTypes": ["click", "shake"]
  }
}

注意:摇一摇激活互动卡片能力仅在 HarmonyOS 7.0 以上版本触发。7.0 以下系统不识别 "shake",配置了也不生效。

4.3 摇一摇触发实现

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

五、破框区域计算

5.1 破框原理

破框(Overflow)是互动卡片的核心特性,允许激活态的渲染区域超出原始卡片边界。破框区域通过 requestOverflowarea 参数指定:

interface OverflowInfo {
  area: {
    left: number;    // 破框区域左上角 X 坐标(相对卡片)
    top: number;     // 破框区域左上角 Y 坐标(相对卡片)
    width: number;   // 破框区域宽度
    height: number;  // 破框区域高度
  };
  duration: number;  // 动画时长(毫秒)
}

5.2 破框区域计算

/**
 * 计算破框区域
 * @param formRect 卡片原始位置和尺寸
 * @param expandRatio 扩展比例(> 1.0 表示破框放大)
 * @returns 破框区域信息
 */
function calculateOverflowArea(
  formRect: formInfo.Rect,
  expandRatio: number
): { left: number; top: number; width: number; height: number } {
  // 计算破框后的尺寸
  const expandedWidth = formRect.width * expandRatio;
  const expandedHeight = formRect.height * expandRatio;

  // 居中偏移(破框区域中心与卡片中心对齐)
  const leftOffset = (formRect.width - expandedWidth) / 2;
  const topOffset = (formRect.height - expandedHeight) / 2;

  return {
    left: leftOffset,
    top: topOffset,
    width: expandedWidth,
    height: expandedHeight
  };
}

5.3 不同卡片的破框参数

卡片 宽度比例 高度比例 动画时长 说明
睡眠卡片 1.5 1.5 5000ms 气球飘出边界,需要较大扩展空间
快递卡片 1.3 1.3 5000ms 憨憨跑动路线,中等扩展
运动卡片 1.4 1.4 5000ms 庆祝动画,需要较大空间
音乐卡片 1.2 1.2 4000ms 专辑飞出,较小扩展

六、常见配置错误与排查

6.1 常见配置错误

错误 原因 解决方案
激活无响应 abilityName 拼写不一致 确保 form_config.jsonmodule.json5 中名称完全一致
摇一摇不触发 系统版本 < 7.0 升级到 HarmonyOS 7.0+
破框区域不对 计算错误 检查 getFormRect 返回值,确保居中计算正确
动画白屏 loadContent 路径错误 检查 livecardability/pages/ 路径是否正确
卡片类型错误 isDynamic 未设置为 true 动态卡片必须设置 isDynamic: true

6.2 配置检查清单

/**
 * 互动卡片配置检查清单
 */
export class LiveFormConfigChecker {
  static checkConfig(formConfig: object, moduleConfig: object): CheckResult {
    const errors: string[] = [];
    const warnings: string[] = [];

    // 1. 检查 isDynamic
    if (!formConfig['isDynamic']) {
      errors.push('isDynamic 必须为 true');
    }

    // 2. 检查 sceneAnimationParams
    const sceneParams = formConfig['sceneAnimationParams'];
    if (!sceneParams || !sceneParams['abilityName']) {
      errors.push('sceneAnimationParams.abilityName 未配置');
    }

    // 3. 检查 module.json5 中的 LiveFormExtensionAbility
    const extAbilities = moduleConfig['extensionAbilities'] || [];
    const liveFormAbility = extAbilities.find(
      (a: Record<string, string>) => a['type'] === 'liveForm'
    );
    if (!liveFormAbility) {
      errors.push('module.json5 中未声明 type 为 liveForm 的 extensionAbility');
    }

    // 4. 检查 abilityName 一致性
    if (sceneParams && liveFormAbility) {
      if (sceneParams['abilityName'] !== liveFormAbility['name']) {
        errors.push(
          `abilityName 不一致: form_config=${sceneParams['abilityName']}, ` +
          `module=${liveFormAbility['name']}`
        );
      }
    }

    // 5. 检查摇一摇版本
    const triggerTypes = sceneParams?.['triggerTypes'] || [];
    if (triggerTypes.includes('shake')) {
      warnings.push('摇一摇触发需要 HarmonyOS 7.0+');
    }

    return {
      isValid: errors.length === 0,
      errors: errors,
      warnings: warnings
    };
  }
}

interface CheckResult {
  isValid: boolean;
  errors: string[];
  warnings: string[];
}

七、总结

在这里插入图片描述

本文从配置与触发角度深入讲解了互动卡片的实战要点:

  • form_config.json 配置sceneAnimationParamsabilityNametriggerTypes 是关键,isDynamic 必须为 true
  • module.json5 声明FormExtensionAbility(type: "form")和 LiveFormExtensionAbility(type: "liveForm")双 Ability 必须同时声明
  • 点击触发:卡片 → postCardAction(MESSAGE)FormExtensionAbility.onFormEventrequestOverflow
  • 摇一摇触发:系统检测 shake → FormExtensionAbility.onUpdateFormrequestOverflow(需 HarmonyOS 7.0+)
  • 破框区域计算:通过 getFormRect 获取卡片尺寸,计算居中偏移,指定 areaduration

下一篇将深入讲解三方通信架构与数据传递,包括动态卡片、应用、互动卡片之间的跨进程通信,点击阅读通信篇 →

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


相关资源:

Logo

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

更多推荐