卡片


无需打开应用,即可从卡片中获取与应用相关的动态信息,甚至可以和卡片交互。

在未来,卡片很可能成为一个巨大的流量入口,进而成为第三方应用厮杀的阵地。

1 什么是卡片

某些应用图标的下方会显示一条横线。凡是图标下方带有横线的应用,都可以在桌面上添加卡片。用手指按住图标的同时向上滑动,就会弹出该应用的默认卡片。点击卡片右上角的图钉,即将卡片固定在桌面上。通过与卡片交互,用户无需打开应用,就可以实现应用内的部分操作。

卡片是应用内页面的展现形式,将页面的重要信息或者操作前置到卡片上,以实现服务直达、减少层级的目标。

2 卡片的数量与大小

一个应用包含一到多个页面(Page Ability)。可以在config.json中为每个页面配置最多16张卡片(form)。这些卡片中最多只能有一张被设置为上滑卡片,即通过上滑应用图标弹出的默认卡片。可以在桌面上添加一个应用的多张卡片,也可以添加一个应用同一张卡片的多个实例。

任何一张卡片的尺寸规格只能取以下四种之一:

3 卡片与原子化服务

原子化服务是一种旨在提供特定功能的,免安装且有独立入口的应用形态。免安装是其区别于传统应用的显著特征。原子化服务是一种面向未来的服务提供方式。

传统应用:

graph LR app_market(应用市场) manage_distribute(管理分发) shopping_app(购物应用) browse_goods(商品浏览页面) shopping_cart(购物车页面) payment(支付页面) app_market-->manage_distribute-->shopping_app shopping_app-->browse_goods shopping_app-->shopping_cart shopping_app-->payment

原子化服务:

graph LR atomized_service_platform(原子化服务平台) manage_distribute(管理分发) browse_goods(商品浏览原子化服务) shopping_cart(购物车原子化服务) payment(支付原子化服务) atomized_service_platform-->manage_distribute manage_distribute-->browse_goods manage_distribute-->shopping_cart manage_distribute-->payment

基于原子化服务理念的设计,商品浏览、购物车和支付会被拆分为三个独立的原子化服务。每个原子化服务只提供特定的功能,而且无需事先安装。只有在用户用到某个原子化服务时,才会在后台自动地从原子化服务平台下载并安装。

一个原子化服务就是一个HAP包,大小不能超过10M字节。该HAP只包含一个FA或PA,完成特定的功能,提供特定的服务。

原子化服务在桌面上是没有图标的。从屏幕左下角或右下角向斜上方滑动,即可进入“服务中心”。在这里可以对所有的原子化服务进行统一地查看、搜索和管理:

原子化服务在“服务中心”以卡片形式显示,可将其添加到桌面。这就是卡片与原子化服务的关系。

例程:Service

从右下角向左上角滑动进入“服务中心”。

4 卡片的总体框架

作为卡片提供方的传统应用或原子化服务,定义了卡片的生命周期回调方法。作为卡片使用方的桌面或服务中心,通过卡片管理服务,与传统应用或原子化服务中的卡片功能交互。

以卡片的定时刷新为例,如果一个卡片在config.json中配置了定时刷新:

  1. 定时器事件通知卡片管理;
  2. 卡片管理找到卡片提供方;
  3. 卡片回调被执行,并将新数据返回给卡片管理;
  4. 卡片管理找到卡片使用方,并传入新数据;
  5. 卡片使用方更新显示。

5 使用JS开发卡片

5.1 创建工程

Empty Ability(JS)
  Project Name: JSForm
  Project Type: Application
  Show in Service Center: Off

entry右键
  New
    Service Widget
      Grid Pattern
        Service Widget Name: MainForm
        Description: Main Form
        Type: JS
        JS Component Name: mainform
        Support Dimensions: 1x2 (2x2)

entry右键
  New
    Service Widget
      Grid Pattern
        Service Widget Name: SecondaryForm
        Description: Secondary Form
        Type: JS
        JS Component Name: secondaryform
        Support Dimensions: (2x2) 2x4 4x4

config.json中的"forms":

"jsComponentName": "mainform",  - 组件名
"isDefault": true,              - 是否为默认上滑
"scheduledUpdateTime": "10:30", - 刷新时刻
"defaultDimension": "2*2",      - 默认尺寸
"name": "MainForm",             - 卡片名
"description": "Main Form",     - 卡片描述
                                  改为“主卡片”,另一个改为“次卡片”
"colorMode": "auto",            - 主题样式
                                  dark、light、auto(默认)
"type": "JS",                   - 卡片类型
"supportDimensions": [          - 支持尺寸
  "1*2",
  "2*2"
],
"updateEnabled": true,          - 是否定时刷新
"updateDuration": 1             - 定时刷新周期
                                  0: 不生效
                                  N: 每隔Nx30分钟刷新一次

5.2 数据绑定

在桌面上长按应用图标然后显示所有卡片,这时MainAbility类的onCreateForm()方法会被回调。本例共有五张卡片,该方法会被回调五次。

protected ProviderFormInfo onCreateForm(Intent intent) {
    HiLog.info(TAG, "onCreateForm");
    // 获取卡片ID
    long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);
    // 获取卡片名称
    String formName = intent.getStringParam(AbilitySlice.PARAM_FORM_NAME_KEY);
    // 获取卡片尺寸
    int dimension = intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY, DEFAULT_DIMENSION_2X2);
    HiLog.info(TAG, "onCreateForm: formId=" + formId + ",formName=" + formName);
    // 创建卡片管理器
    FormControllerManager formControllerManager = FormControllerManager.getInstance(this);
    // 根据卡片ID获取(创建)相应的卡片控制器
    FormController formController = formControllerManager.getController(formId);
    formController = (formController == null) ? formControllerManager.createFormController(formId,
            formName, dimension) : formController;
    if (formController == null) {
        HiLog.error(TAG, "Get null controller. formId: " + formId + ", formName: " + formName);
        return null;
    }
    // 绑定卡片数据
    return formController.bindFormData();
}

在MainFormImpl类中添加:

private static final int DIMENSION_2X2 = 2;

在MainFormImpl类的bindFormData()方法中添加:

public ProviderFormInfo bindFormData() {
    HiLog.info(TAG, "bind form data");
    ZSONObject zsonObject = new ZSONObject();
    ProviderFormInfo providerFormInfo = new ProviderFormInfo();
    if (dimension == DIMENSION_1X2) {
        zsonObject.put("mini", true);
        zsonObject.put("miniTitle", "主卡片(1×2)");
    }
    if (dimension == DIMENSION_2X2) {
        zsonObject.put("title", "主卡片(2×2)");
        zsonObject.put("content", "两行两列的主卡片");
    }
    if (dimension == DIMENSION_2X4) {
        zsonObject.put("dim2X4", true);
    }
    providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
    return providerFormInfo;
}

运行效果如下图所示:

在SecondaryFormImpl类中添加:

private static final int DIMENSION_2X2 = 2;
private static final int DIMENSION_4X4 = 4;

在SecondaryFormImpl类的bindFormData()方法中添加:

public ProviderFormInfo bindFormData() {
    HiLog.info(TAG, "bind form data");
    ZSONObject zsonObject = new ZSONObject();
    ProviderFormInfo providerFormInfo = new ProviderFormInfo();
    if (dimension == DIMENSION_1X2) {
        zsonObject.put("mini", true);
    }
    if (dimension == DIMENSION_2X2) {
        zsonObject.put("title", "次卡片(2×2)");
        zsonObject.put("content", "两行两列的次卡片");
    }
    if (dimension == DIMENSION_2X4) {
        zsonObject.put("dim2X4", true);
        zsonObject.put("title", "次卡片(2×4)");
        zsonObject.put("content", "两行四列的次卡片");
    }
    if (dimension == DIMENSION_4X4) {
        zsonObject.put("title", "次卡片(4×4)");
        zsonObject.put("content", "四行四列的次卡片");
    }
    providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
    return providerFormInfo;
}

运行效果如下图所示:

 

5.3 定时刷新

在SecondaryFormImpl类的updateFormData()方法中添加:

public void updateFormData(long formId, Object... vars) {
    HiLog.info(TAG, "update form data timing, default 30 minutes");

    Date date = Calendar.getInstance().getTime();
    SimpleDateFormat formatter = new SimpleDateFormat("H:mm:ss");
    String time = formatter.format(date);

    ZSONObject zsonObject = new ZSONObject();
    zsonObject.put("content", time);

    FormBindingData formBindingData =
        new FormBindingData(zsonObject);
    try {
        ((MainAbility)context).updateForm(formId, formBindingData);
    }
    catch (FormException exception) {
        HiLog.error(TAG, exception.toString());
    }
}

修改config.json中关于次卡片的配置:

...
"scheduledUpdateTime": "17:30",
...
"updateDuration": 0,
...

当17:30到达时,次卡片所有尺寸的内容字符串都更新为当前时间。

运行效果如下图所示:

 

5.4 卡片跳转

entry右键
  New
    Ability
      Empty Page Ability(Java)
        Page Name: SecondaryAbility

在secondaryform/pages/index/index.json中添加:

"actions": {
  "secondaryAbility": {
    "action": "router",
    "abilityName": "com.minwei.jsform.SecondaryAbility",
    "params": {
      "country": "中国",
      "province": "北京"
    }
  }
}

在secondaryform/pages/index/index.hml中添加:

<image src="/common/image_1.png" class="title_img" onclick="secondaryAbility"></image>

在SecondaryAbilitySlice类的onStart()方法中添加:

public void onStart(Intent intent) {
    ...
    ZSONObject zsonObject = ZSONObject.stringToZSON(
        intent.getStringParam("params"));
    String country = zsonObject.getString("country");
    String province = zsonObject.getString("province");

    ((Text)findComponentById(ResourceTable.Id_text_helloworld))
        .setText(country + "·" + province);
}

点击任意尺寸次卡片左上角的图标,都会打开次页面,并显示“中国·北京”。

运行效果如下图所示:

5.5 卡片消息

在secondaryform/pages/index/index.json中添加:

"actions": {
  ...
  "sendMessage": {
    "action": "message",
    "params": {
      "country": "中国",
      "province": "北京"
    }
  }
}

在secondaryform/pages/index/index.hml中添加:

<div class="normal_container" onclick="sendMessage">

在SecondaryFormImpl类的onTriggerFormEvent()方法中添加:

public void onTriggerFormEvent(long formId, String message) {
    HiLog.info(TAG, "handle card click event.");

    ZSONObject zsonObject = ZSONObject.stringToZSON(message);
    String country = zsonObject.getString("country");
    String province = zsonObject.getString("province");

    zsonObject = new ZSONObject();
    zsonObject.put("title", country);
    zsonObject.put("content", province);

    FormBindingData formBindingData =
        new FormBindingData(zsonObject);
    try {
        ((MainAbility)context).updateForm(formId, formBindingData);
    }
    catch (FormException exception) {
        HiLog.error(TAG, exception.toString());
    }
}

点击次卡片空白区,被点击卡片的标题和内容更新为“中国”和“北京”。

运行效果如下图所示:

 

例程:JSForm

...\JSForm\entry\src\main\config.json

{
  ...
  "module": {
    ...
    "abilities": [
      {
        ...
        "forms": [
          {
            "jsComponentName": "mainform",
            "isDefault": true,
            "scheduledUpdateTime": "10:30",
            "defaultDimension": "2*2",
            "name": "MainForm",
            "description": "主卡片",
            "colorMode": "auto",
            "type": "JS",
            "supportDimensions": [
              "1*2",
              "2*2"
            ],
            "updateEnabled": true,
            "updateDuration": 1
          },
          {
            "jsComponentName": "secondaryform",
            "isDefault": false,
            "scheduledUpdateTime": "17:30",
            "defaultDimension": "2*2",
            "name": "SecondaryForm",
            "description": "次卡片",
            "colorMode": "auto",
            "type": "JS",
            "supportDimensions": [
              "2*2",
              "2*4",
              "4*4"
            ],
            "updateEnabled": true,
            "updateDuration": 0
          }
        ]
      },
      ...
    ],
    ...
  }
}

...\JSForm\entry\src\main\js\secondaryform\pages\index\index.json

{
  ...
  "actions": {
    "secondaryAbility": {
      "action": "router",
      "abilityName": "com.minwei.jsform.SecondaryAbility",
      "params": {
        "country": "中国",
        "province": "北京"
      }
    },
    "sendMessage": {
      "action": "message",
      "params": {
        "country": "中国",
        "province": "北京"
      }
    }
  }
}

...\JSForm\entry\src\main\js\secondaryform\pages\index\index.hml

<div class="grid_pattern_layout">
    ...
    <div class="normal_container" onclick="sendMessage">
        <div class="title_container">
            <div class="pic_title_container">
                <image src="/common/image_1.png" class="title_img" onclick="secondaryAbility"></image>
                ...
            </div>
            ...
        </div>
        ...
    </div>
</div>

...\JSForm\entry\src\main\java\com\minwei\jsform\widget\mainform\MainFormImpl.java

public class MainFormImpl extends FormController {
    ...
    private static final int DIMENSION_2X2 = 2;
    ...
    @Override
    public ProviderFormInfo bindFormData() {
        HiLog.info(TAG, "bind form data");
        ZSONObject zsonObject = new ZSONObject();
        ProviderFormInfo providerFormInfo = new ProviderFormInfo();
        if (dimension == DIMENSION_1X2) {
            zsonObject.put("mini", true);
            zsonObject.put("miniTitle", "主卡片(1×2)");
        }
        if (dimension == DIMENSION_2X2) {
            zsonObject.put("title", "主卡片(2×2)");
            zsonObject.put("content", "两行两列的主卡片");
        }
        if (dimension == DIMENSION_2X4) {
            zsonObject.put("dim2X4", true);
        }
        providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
        return providerFormInfo;
    }
    ...
}

...\JSForm\entry\src\main\java\com\minwei\jsform\widget\secondaryform\SecondaryFormImpl.java

public class SecondaryFormImpl extends FormController {
    ...
    private static final int DIMENSION_2X2 = 2;
    ...
    private static final int DIMENSION_4X4 = 4;
    ...
    @Override
    public ProviderFormInfo bindFormData() {
        HiLog.info(TAG, "bind form data");
        ZSONObject zsonObject = new ZSONObject();
        ProviderFormInfo providerFormInfo = new ProviderFormInfo();
        if (dimension == DIMENSION_1X2) {
            zsonObject.put("mini", true);
        }
        if (dimension == DIMENSION_2X2) {
            zsonObject.put("title", "次卡片(2×2)");
            zsonObject.put("content", "两行两列的次卡片");
        }
        if (dimension == DIMENSION_2X4) {
            zsonObject.put("dim2X4", true);
            zsonObject.put("title", "次卡片(2×4)");
            zsonObject.put("content", "两行四列的次卡片");
        }
        if (dimension == DIMENSION_4X4) {
            zsonObject.put("title", "次卡片(4×4)");
            zsonObject.put("content", "四行四列的次卡片");
        }
        providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
        return providerFormInfo;
    }

    @Override
    public void updateFormData(long formId, Object... vars) {
        HiLog.info(TAG, "update form data timing, default 30 minutes");

        Date date = Calendar.getInstance().getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("H:mm:ss");
        String time = formatter.format(date);

        ZSONObject zsonObject = new ZSONObject();
        zsonObject.put("content", time);

        FormBindingData formBindingData =
            new FormBindingData(zsonObject);
        try {
            ((MainAbility)context).updateForm(formId, formBindingData);
        }
        catch (FormException exception) {
            HiLog.error(TAG, exception.toString());
        }
    }

    @Override
    public void onTriggerFormEvent(long formId, String message) {
        HiLog.info(TAG, "handle card click event.");

        ZSONObject zsonObject = ZSONObject.stringToZSON(message);
        String country = zsonObject.getString("country");
        String province = zsonObject.getString("province");

        zsonObject = new ZSONObject();
        zsonObject.put("title", country);
        zsonObject.put("content", province);

        FormBindingData formBindingData =
            new FormBindingData(zsonObject);
        try {
            ((MainAbility)context).updateForm(formId, formBindingData);
        }
        catch (FormException exception) {
            HiLog.error(TAG, exception.toString());
        }
    }
    ...
}

...\JSForm\entry\src\main\java\com\minwei\jsform\slice\SecondaryAbilitySlice.java

public class SecondaryAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        ...
        ZSONObject zsonObject = ZSONObject.stringToZSON(
            intent.getStringParam("params"));
        String country = zsonObject.getString("country");
        String province = zsonObject.getString("province");

        ((Text)findComponentById(ResourceTable.Id_text_helloworld))
            .setText(country + "·" + province);
    }
    ...
}

6 使用Java开发卡片

6.1 创建工程

Empty Ability(Java)
  JavaForm
    Project Type: Application
    Show in Service Center: Off

entry右键
  New
    Service Widget
      Grid Pattern
        Service Widget Name: MainForm
        Description: Main Form
        Type: Java
        Support Dimensions: 1x2 (2x2)

entry右键
  New
    Service Widget
      Grid Pattern
        Service Widget Name: SecondaryForm
        Description: Secondary Form
        Type: Java
        Support Dimensions: (2x2) 2x4 4x4

config.json中的"forms":

"landscapeLayouts": [           - 横屏布局
  "$layout:form_grid_pattern_mainform_1_2",
  "$layout:form_grid_pattern_mainform_2_2"
],
"isDefault": true,              - 是否为默认上滑
"scheduledUpdateTime": "10:30", - 刷新时刻
"defaultDimension": "2*2",      - 默认尺寸
"name": "MainForm",             - 卡片名
"description": "Main Form",     - 卡片描述
                                  改为“主卡片”,另一个改为“次卡片”
"colorMode": "auto",            - 主题样式
                                  dark、light、auto(默认)
"type": "Java",
"supportDimensions": [          - 支持尺寸
  "1*2",
  "2*2"
],
"portraitLayouts": [            - 竖屏布局
  "$layout:form_grid_pattern_mainform_1_2",
  "$layout:form_grid_pattern_mainform_2_2"
],
"updateEnabled": true,          - 是否定时刷新
"updateDuration": 1             - 定时刷新周期
                                  0: 不生效
                                  N: 每隔Nx30分钟刷新一次

6.2 数据绑定

在主卡片的两个布局文件form_grid_pattern_mainform_1_2.xml和form_grid_pattern_mainform_2_2.xml中为文本框组件添加ID:

<Text
    ohos:id="$+id:title"
    ...
    ohos:text="$string:mainform_title"
    .../>
<Text
    ohos:id="$+id:content"
    ...
    ohos:text="$string:mainform_introduction"
    .../>

在MainFormImpl类的bindFormData()方法中添加:

public ProviderFormInfo bindFormData() {
    HiLog.info(TAG, "bind form data when create form");
    ProviderFormInfo providerFormInfo =
        new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);
    ComponentProvider componentProvider = new ComponentProvider();
    if (dimension == DIMENSION_1X2) {
        componentProvider.setText(ResourceTable.Id_title, "主卡片(1×2)");
    }
    if (dimension == DEFAULT_DIMENSION_2X2) {
        componentProvider.setText(ResourceTable.Id_title, "主卡片(2×2)");
        componentProvider.setText(ResourceTable.Id_content, "两行两列的主卡片");
    }
    providerFormInfo.mergeActions(componentProvider);
    return providerFormInfo;
}

运行效果如下图所示:

在次卡片的三个布局文件form_grid_pattern_secondaryform_2_2.xml、form_grid_pattern_secondaryform_2_4.xml和form_grid_pattern_secondaryform_4_4.xml中为文本框组件添加ID:

<Text
    ohos:id="$+id:title"
    ...
    ohos:text="$string:secondaryform_title"
    .../>
<Text
    ohos:id="$+id:content"
    ...
    ohos:text="$string:secondaryform_introduction"
    .../>

在SecondaryFormImpl类的bindFormData()方法中添加:

public ProviderFormInfo bindFormData() {
    HiLog.info(TAG, "bind form data when create form");
    ProviderFormInfo providerFormInfo =
            new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);
    ComponentProvider componentProvider = new ComponentProvider();
    if (dimension == DEFAULT_DIMENSION_2X2) {
        componentProvider.setText(ResourceTable.Id_title, "次卡片(2×2)");
        componentProvider.setText(ResourceTable.Id_content, "两行两列的次卡片");
    }
    if (dimension == DIMENSION_2X4) {
        componentProvider.setText(ResourceTable.Id_title, "次卡片(2×4)");
        componentProvider.setText(ResourceTable.Id_content, "两行四列的次卡片");
    }
    if (dimension == DIMENSION_4X4) {
        componentProvider.setText(ResourceTable.Id_title, "次卡片(4×4)");
        componentProvider.setText(ResourceTable.Id_content, "四行四列的次卡片");
    }
    providerFormInfo.mergeActions(componentProvider);
    return providerFormInfo;
}

运行效果如下图所示:

 

6.3 定时刷新

在SecondaryFormImpl类的updateFormData()方法中添加:

public void updateFormData(long formId, Object... vars) {
    HiLog.info(TAG, "update form data timing, default 30 minutes");

    Date date = Calendar.getInstance().getTime();
    SimpleDateFormat formatter = new SimpleDateFormat("H:mm:ss");
    String time = formatter.format(date);

    ComponentProvider componentProvider = new ComponentProvider(
        RESOURCE_ID_MAP.get(dimension), context);
    componentProvider.setText(ResourceTable.Id_content, time);

    try {
        ((MainAbility)context).updateForm(formId, componentProvider);
    }
    catch (FormException exception) {
        HiLog.error(TAG, exception.toString());
    }
}

修改config.json中关于次卡片的配置:

...
"scheduledUpdateTime": "17:30",
...
"updateDuration": 0,
...

当17:30到达时,次卡片所有尺寸的内容字符串都更新为当前时间。

运行效果如下图所示:

 

6.4 卡片跳转

entry右键
  New
    Ability
      Empty Page Ability(Java)
        Page Name: SecondaryAbility

在次卡片所有尺寸的布局文件中为左上角图标添加ID:

<Image
    ohos:id="$+id:logo"
    ...
    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_2"
    .../>

在SecondaryFormImpl类的bindFormData()方法中添加:

public ProviderFormInfo bindFormData() {
    ...
    OperationBuilder operationBuilder = new OperationBuilder();
    operationBuilder.withDeviceId("");
    operationBuilder.withBundleName("com.minwei.javaform");
    operationBuilder.withAbilityName(
        "com.minwei.javaform.SecondaryAbility");
    Operation operation = operationBuilder.build();
    Intent intent = new Intent();
    intent.setOperation(operation);
    intent.setParam("country", "中国");
    intent.setParam("province", "北京");
    List<Intent> intents = new ArrayList<>();
    intents.add(intent);
    List<Flags> flags = new ArrayList<>();
    flags.add(Flags.UPDATE_PRESENT_FLAG);
    IntentAgentInfo intentAgentInfo = new IntentAgentInfo(
        200, OperationType.START_ABILITY, flags, intents, null);
    IntentAgent intentAgent = IntentAgentHelper.getIntentAgent(
        context, intentAgentInfo);
    componentProvider.setIntentAgent(
        ResourceTable.Id_logo, intentAgent);
    ...
}

在SecondaryAbilitySlice类的onStart()方法中添加:

public void onStart(Intent intent) {
    ...
    String country = intent.getStringParam("country");
    String province = intent.getStringParam("province");

    ((Text)findComponentById(ResourceTable.Id_text_helloworld))
        .setText(country + "·" + province);
}

点击任意尺寸次卡片左上角的图标,都会打开次页面,并显示“中国·北京”。

运行效果如下图所示:

例程:JavaForm

...\JavaForm\entry\src\main\config.json

{
  ...
  "module": {
    ...
    "abilities": [
      {
        ...
        "forms": [
          {
            "landscapeLayouts": [
              "$layout:form_grid_pattern_mainform_1_2",
              "$layout:form_grid_pattern_mainform_2_2"
            ],
            "isDefault": true,
            "scheduledUpdateTime": "10:30",
            "defaultDimension": "2*2",
            "name": "MainForm",
            "description": "主卡片",
            "colorMode": "auto",
            "type": "Java",
            "supportDimensions": [
              "1*2",
              "2*2"
            ],
            "portraitLayouts": [
              "$layout:form_grid_pattern_mainform_1_2",
              "$layout:form_grid_pattern_mainform_2_2"
            ],
            "updateEnabled": true,
            "updateDuration": 1
          },
          {
            "landscapeLayouts": [
              "$layout:form_grid_pattern_secondaryform_2_2",
              "$layout:form_grid_pattern_secondaryform_2_4",
              "$layout:form_grid_pattern_secondaryform_4_4"
            ],
            "isDefault": false,
            "scheduledUpdateTime": "17:30",
            "defaultDimension": "2*2",
            "name": "SecondaryForm",
            "description": "次卡片",
            "colorMode": "auto",
            "type": "Java",
            "supportDimensions": [
              "2*2",
              "2*4",
              "4*4"
            ],
            "portraitLayouts": [
              "$layout:form_grid_pattern_secondaryform_2_2",
              "$layout:form_grid_pattern_secondaryform_2_4",
              "$layout:form_grid_pattern_secondaryform_4_4"
            ],
            "updateEnabled": true,
            "updateDuration": 0
          }
        ]
      },
      ...
    ]
  }
}

...\JavaForm\entry\src\main\resources\base\layout\form_grid_pattern_mainform_1_2.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#FF007DFB"
    ohos:orientation="horizontal"
    ohos:remote="true">

    <Image
        ohos:height="30vp"
        ohos:width="30vp"
        ohos:image_src="$media:form_grid_pattern_mainform_default_image_1"
        ohos:layout_alignment="vertical_center"
        ohos:scale_mode="zoom_center"
        ohos:start_margin="12vp"/>

    <Text
        ohos:id="$+id:title"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:end_margin="12vp"
        ohos:layout_alignment="vertical_center"
        ohos:start_margin="8vp"
        ohos:text="$string:mainform_title"
        ohos:text_color="#E5FFFFFF"
        ohos:text_size="14fp"
        ohos:text_weight="500"
        ohos:truncation_mode="ellipsis_at_end"/>
</DirectionalLayout>

...\JavaForm\entry\src\main\resources\base\layout\form_grid_pattern_mainform_2_2.xml

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#FF007DFB"
    ohos:remote="true">

    <Image
        ohos:height="60vp"
        ohos:width="60vp"
        ohos:image_src="$media:form_grid_pattern_mainform_default_image_2"
        ohos:scale_mode="zoom_start"
        ohos:start_margin="12vp"
        ohos:top_margin="12vp"/>

    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:align_parent_bottom="true"
        ohos:bottom_margin="12vp"
        ohos:end_margin="12vp"
        ohos:orientation="vertical"
        ohos:start_margin="12vp">

        <Text
            ohos:id="$+id:title"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:text="$string:mainform_title"
            ohos:text_color="#E5FFFFFF"
            ohos:text_size="14fp"
            ohos:text_weight="500"
            ohos:truncation_mode="ellipsis_at_end"/>

        <Text
            ohos:id="$+id:content"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:text="$string:mainform_introduction"
            ohos:text_color="#99FFFFFF"
            ohos:text_size="10fp"
            ohos:text_weight="400"
            ohos:top_margin="2vp"
            ohos:truncation_mode="ellipsis_at_end"/>
    </DirectionalLayout>
</DependentLayout>

...\JavaForm\entry\src\main\resources\base\layout\form_grid_pattern_secondaryform_2_2.xml

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#FF007DFB"
    ohos:remote="true">

    <Image
        ohos:id="$+id:logo"
        ohos:height="60vp"
        ohos:width="60vp"
        ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_2"
        ohos:scale_mode="zoom_start"
        ohos:start_margin="12vp"
        ohos:top_margin="12vp"/>

    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:align_parent_bottom="true"
        ohos:bottom_margin="12vp"
        ohos:end_margin="12vp"
        ohos:orientation="vertical"
        ohos:start_margin="12vp">

        <Text
            ohos:id="$+id:title"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:text="$string:secondaryform_title"
            ohos:text_color="#E5FFFFFF"
            ohos:text_size="14fp"
            ohos:text_weight="500"
            ohos:truncation_mode="ellipsis_at_end"/>

        <Text
            ohos:id="$+id:content"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:text="$string:secondaryform_introduction"
            ohos:text_color="#99FFFFFF"
            ohos:text_size="10fp"
            ohos:text_weight="400"
            ohos:top_margin="2vp"
            ohos:truncation_mode="ellipsis_at_end"/>
    </DirectionalLayout>
</DependentLayout>

...\JavaForm\entry\src\main\resources\base\layout\form_grid_pattern_secondaryform_2_4.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="horizontal"
    ohos:remote="true">

    <DependentLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="#FF007DFB"
        ohos:weight="1">

        <Image
            ohos:id="$+id:logo"
            ohos:height="60vp"
            ohos:width="60vp"
            ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_2"
            ohos:scale_mode="zoom_start"
            ohos:start_margin="12vp"
            ohos:top_margin="12vp"/>

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:align_parent_bottom="true"
            ohos:bottom_margin="12vp"
            ohos:end_margin="12vp"
            ohos:orientation="vertical"
            ohos:start_margin="12vp">

            <Text
                ohos:id="$+id:title"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:text="$string:secondaryform_title"
                ohos:text_color="#E5FFFFFF"
                ohos:text_size="14fp"
                ohos:text_weight="500"
                ohos:truncation_mode="ellipsis_at_end"/>

            <Text
                ohos:id="$+id:content"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:text="$string:secondaryform_introduction"
                ohos:text_color="#99FFFFFF"
                ohos:text_size="10fp"
                ohos:text_weight="400"
                ohos:top_margin="2vp"
                ohos:truncation_mode="ellipsis_at_end"/>
        </DirectionalLayout>
    </DependentLayout>

    <DirectionalLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="#FFFFFFFF"
        ohos:bottom_padding="6vp"
        ohos:end_padding="8vp"
        ohos:orientation="vertical"
        ohos:start_padding="8vp"
        ohos:top_padding="6vp"
        ohos:weight="1">

        <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:orientation="horizontal"
            ohos:top_margin="6vp"
            ohos:weight="1">

            <DependentLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1">

                <Image
                    ohos:height="57vp"
                    ohos:width="57vp"
                    ohos:center_in_parent="true"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_3"
                    ohos:scale_mode="zoom_center"/>
            </DependentLayout>

            <DependentLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1">

                <Image
                    ohos:height="57vp"
                    ohos:width="57vp"
                    ohos:center_in_parent="true"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_3"
                    ohos:scale_mode="zoom_center"/>
            </DependentLayout>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:orientation="horizontal"
            ohos:top_margin="6vp"
            ohos:weight="1">

            <DependentLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1">

                <Image
                    ohos:height="57vp"
                    ohos:width="57vp"
                    ohos:center_in_parent="true"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_3"
                    ohos:scale_mode="zoom_center"/>
            </DependentLayout>

            <DependentLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1">

                <Image
                    ohos:height="57vp"
                    ohos:width="57vp"
                    ohos:center_in_parent="true"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_3"
                    ohos:scale_mode="zoom_center"/>
            </DependentLayout>
        </DirectionalLayout>
    </DirectionalLayout>
</DirectionalLayout>

...\JavaForm\entry\src\main\resources\base\layout\form_grid_pattern_secondaryform_4_4.xml

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:remote="true">

    <DependentLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:align_parent_bottom="true"
        ohos:background_element="#FF007DFB"
        ohos:bottom_margin="198vp">

        <Image
            ohos:id="$+id:logo"
            ohos:height="60vp"
            ohos:width="60vp"
            ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_2"
            ohos:scale_mode="zoom_start"
            ohos:start_margin="12vp"
            ohos:top_margin="12vp"/>

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:align_parent_bottom="true"
            ohos:bottom_margin="12vp"
            ohos:end_margin="12vp"
            ohos:orientation="vertical"
            ohos:start_margin="12vp">

            <Text
                ohos:id="$+id:title"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:text="$string:secondaryform_title"
                ohos:text_color="#E5FFFFFF"
                ohos:text_size="14fp"
                ohos:text_weight="500"
                ohos:truncation_mode="ellipsis_at_end"/>

            <Text
                ohos:id="$+id:content"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:text="$string:secondaryform_introduction"
                ohos:text_color="#99FFFFFF"
                ohos:text_size="10fp"
                ohos:text_weight="400"
                ohos:top_margin="2vp"
                ohos:truncation_mode="ellipsis_at_end"/>
        </DirectionalLayout>
    </DependentLayout>

    <DependentLayout
        ohos:height="198vp"
        ohos:width="match_parent"
        ohos:align_parent_bottom="true"
        ohos:background_element="#FFFFFFFF">

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:center_in_parent="true"
            ohos:end_margin="8vp"
            ohos:orientation="horizontal"
            ohos:start_margin="8vp">

            <DirectionalLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:orientation="vertical"
                ohos:weight="1">

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>
            </DirectionalLayout>

            <DirectionalLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:orientation="vertical"
                ohos:weight="1">

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>
            </DirectionalLayout>

            <DirectionalLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:orientation="vertical"
                ohos:weight="1">

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>
            </DirectionalLayout>

            <DirectionalLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:orientation="vertical"
                ohos:weight="1">

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>

                <Image
                    ohos:height="64vp"
                    ohos:width="64vp"
                    ohos:image_src="$media:form_grid_pattern_secondaryform_default_image_4"
                    ohos:layout_alignment="horizontal_center"
                    ohos:scale_mode="zoom_center"
                    ohos:top_margin="12vp"/>

                <Text
                    ohos:height="match_content"
                    ohos:width="64vp"
                    ohos:layout_alignment="horizontal_center"
                    ohos:text="$string:secondaryform_title"
                    ohos:text_alignment="horizontal_center"
                    ohos:text_color="#E5000000"
                    ohos:text_size="12fp"
                    ohos:text_weight="500"
                    ohos:top_margin="2vp"
                    ohos:truncation_mode="ellipsis_at_end"/>
            </DirectionalLayout>
        </DirectionalLayout>
    </DependentLayout>
</DependentLayout>

...\JavaForm\entry\src\main\java\com\minwei\javaform\widget\mainform\MainFormImpl.java

public class MainFormImpl extends FormController {
    ...
    @Override
    public ProviderFormInfo bindFormData() {
        HiLog.info(TAG, "bind form data when create form");
        ProviderFormInfo providerFormInfo =
            new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);
        ComponentProvider componentProvider = new ComponentProvider();
        if (dimension == DIMENSION_1X2)
            componentProvider.setText(ResourceTable.Id_title, "主卡片(1×2)");
        if (dimension == DEFAULT_DIMENSION_2X2) {
            componentProvider.setText(ResourceTable.Id_title, "主卡片(2×2)");
            componentProvider.setText(ResourceTable.Id_content, "两行两列的主卡片");
        }
        providerFormInfo.mergeActions(componentProvider);
        return providerFormInfo;
    }
    ...
}

...\JavaForm\entry\src\main\java\com\minwei\javaform\widget\secondaryform\SecondaryFormImpl.java

public class SecondaryFormImpl extends FormController {
    ...
    @Override
    public ProviderFormInfo bindFormData() {
        HiLog.info(TAG, "bind form data when create form");
        ProviderFormInfo providerFormInfo =
            new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);
        ComponentProvider componentProvider = new ComponentProvider();
        if (dimension == DEFAULT_DIMENSION_2X2) {
            componentProvider.setText(ResourceTable.Id_title, "次卡片(2×2)");
            componentProvider.setText(ResourceTable.Id_content, "两行两列的次卡片");
        }
        if (dimension == DIMENSION_2X4) {
            componentProvider.setText(ResourceTable.Id_title, "次卡片(2×4)");
            componentProvider.setText(ResourceTable.Id_content, "两行四列的次卡片");
        }
        if (dimension == DIMENSION_4X4) {
            componentProvider.setText(ResourceTable.Id_title, "次卡片(4×4)");
            componentProvider.setText(ResourceTable.Id_content, "四行四列的次卡片");
        }
        OperationBuilder operationBuilder = new OperationBuilder();
        operationBuilder.withDeviceId("");
        operationBuilder.withBundleName("com.minwei.javaform");
        operationBuilder.withAbilityName(
            "com.minwei.javaform.SecondaryAbility");
        Operation operation = operationBuilder.build();
        Intent intent = new Intent();
        intent.setOperation(operation);
        intent.setParam("country", "中国");
        intent.setParam("province", "北京");
        List<Intent> intents = new ArrayList<>();
        intents.add(intent);
        List<Flags> flags = new ArrayList<>();
        flags.add(Flags.UPDATE_PRESENT_FLAG);
        IntentAgentInfo intentAgentInfo = new IntentAgentInfo(
            200, OperationType.START_ABILITY, flags, intents, null);
        IntentAgent intentAgent = IntentAgentHelper.getIntentAgent(
            context, intentAgentInfo);
        componentProvider.setIntentAgent(
            ResourceTable.Id_logo, intentAgent);
        providerFormInfo.mergeActions(componentProvider);
        return providerFormInfo;
    }

    @Override
    public void updateFormData(long formId, Object... vars) {
        HiLog.info(TAG, "update form data timing, default 30 minutes");

        Date date = Calendar.getInstance().getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("H:mm:ss");
        String time = formatter.format(date);

        ComponentProvider componentProvider = new ComponentProvider(
            RESOURCE_ID_MAP.get(dimension), context);
        componentProvider.setText(ResourceTable.Id_content, time);

        try {
            ((MainAbility)context).updateForm(formId, componentProvider);
        }
        catch (FormException exception) {
            HiLog.error(TAG, exception.toString());
        }
    }
    ...
}

...\JavaForm\entry\src\main\java\com\minwei\javaform\slice\SecondaryAbilitySlice.java

public class SecondaryAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        ...
        String country = intent.getStringParam("country");
        String province = intent.getStringParam("province");

        ((Text)findComponentById(ResourceTable.Id_text_helloworld))
            .setText(country + "·" + province);
    }
    ...
}

7 使用JS和使用Java开发卡片对比

结论:

更多精彩,敬请期待……


达内集团C++教学部 2021年9月24日