本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、卡片编辑

卡片编辑是ArkTS卡片提供的一种页面编辑能力,允许用户自定义卡片的内容和样式。卡片提供方可以实现自己的编辑页面,让用户按需配置卡片。

实现原理

卡片编辑采用两级编辑页的设计:

用户点击卡片编辑
    ↓
卡片使用方(桌面)检测到卡片支持编辑
    ↓
拉起卡片提供方的一级编辑页 (FormEditExtensionAbility)
    ↓
一级编辑页通过 startSecondPage 拉起二级编辑页
    ↓
用户在二级编辑页完成编辑操作
    ↓
编辑后的数据通过 updateForm 刷新卡片

核心组件

组件 作用
FormEditExtensionAbility 卡片编辑扩展能力,提供编辑页生命周期
FormEditExtensionContext 编辑上下文,提供startSecondPage方法
UIExtensionContentSession 管理UI扩展会话,用于加载页面

二、开发步骤

2.1 创建FormEditExtensionAbility

首先,在工程的entry模块中创建EntryFormEditAbility.ets文件,继承FormEditExtensionAbility

// src/main/ets/entryformeditability/EntryFormEditAbility.ets

import { FormEditExtensionAbility } from '@kit.FormKit';
import { Want, UIExtensionContentSession } from '@kit.AbilityKit';
import { ExtensionEvent } from '../pages/model/ExtensionEvent';

const TAG: string = 'FormEditDemo[EntryFormEditAbility] -->';

export default class EntryFormEditAbility extends FormEditExtensionAbility {
    
    // 创建时回调
    onCreate() {
        console.info(`${TAG} onCreate`);
    }
    
    // 切换到前台时回调
    onForeground(): void {
        console.info(`${TAG} onForeground.....`);
    }
    
    // 切换到后台时回调
    onBackground(): void {
        console.info(`${TAG} onBackground......`);
    }
    
    // 销毁时回调
    onDestroy(): void {
        console.info(`${TAG} onDestroy......`);
    }
    
    // 会话创建时回调(核心方法)
    onSessionCreate(want: Want, session: UIExtensionContentSession) {
        console.info(`${TAG} onSessionCreate start..... want: ${JSON.stringify(want)}`);
        
        // 创建LocalStorage用于数据传递
        let storage: LocalStorage = new LocalStorage();
        
        // 创建ExtensionEvent对象,用于调用startSecondPage
        let extensionEvent: ExtensionEvent = new ExtensionEvent();
        extensionEvent.setStartSecondPage(() => this.startSecondPage());
        storage.setOrCreate('extensionEvent', extensionEvent);
        
        // 加载一级编辑页面
        try {
            session.loadContent('pages/Extension', storage);
        } catch (e) {
            console.error(`${TAG} EntryFormEditAbility loadContent err: ${JSON.stringify(e)}`);
        }
    }
    
    // 会话销毁时回调
    onSessionDestroy(session: UIExtensionContentSession) {
        console.info(`${TAG} onSessionDestroy`);
    }
    
    // 拉起二级编辑页的方法
    private startSecondPage(): void {
        const bundleName: string = this.context.extensionAbilityInfo.bundleName;
        const secPageAbilityName: string = 'FormEditSecPageAbility';
        
        console.info(`${TAG} startSecondPage. bundleName: ${bundleName}, secPageAbilityName: ${secPageAbilityName}.`);
        
        try {
            // 调用startSecondPage拉起二级编辑页
            this.context.startSecondPage({
                bundleName: bundleName,
                parameters: {
                    "secPageAbilityName": secPageAbilityName
                }
            });
        } catch (err) {
            console.error(`${TAG} startSecondPage failed: ${err}`);
        }
    }
}

2.2 创建ExtensionEvent工具类

ExtensionEvent类用于在一级编辑页中调用startSecondPage方法。

// src/main/ets/pages/model/ExtensionEvent.ets

const TAG: string = 'FormEditDemo[ExtensionEvent] -->';

export class ExtensionEvent {
    private startSecondPage: () => void = () => {
        console.info(`${TAG} startSecondPage is empty!`);
    };
    
    // 设置startSecondPage方法
    public setStartSecondPage(startSecondPage: () => void) {
        console.info(`${TAG} setStartSecondPage`);
        this.startSecondPage = startSecondPage;
    }
    
    // 调用startSecondPage方法
    public startFormEditSecondPage(): void {
        console.info(`${TAG} startFormEditSecondPage`);
        this.startSecondPage();
    }
}

2.3 创建一级编辑页面

一级编辑页面是用户点击"编辑"后首先看到的页面。

// src/main/ets/pages/Extension.ets

import { UIExtensionContentSession } from '@kit.AbilityKit';
import { ExtensionEvent } from './model/ExtensionEvent';

let storage = new LocalStorage();
const TAG: string = 'FormEditDemo[Extension] -->';

@Entry(storage)
@Component
struct Extension {
    @State message: string = 'UIExtension Provider';
    private session: UIExtensionContentSession | undefined = storage.get<UIExtensionContentSession>('session');
    private extensionEvent: ExtensionEvent | undefined = storage.get<ExtensionEvent>('extensionEvent');
    
    onPageShow() {
        console.info(`${TAG} onPageShow. extensionEvent: ${JSON.stringify(this.extensionEvent)}`);
    }
    
    build() {
        Row() {
            Column() {
                // 标题
                Text(this.message)
                    .fontSize(20)
                    .fontWeight(FontWeight.Bold)
                    .textAlign(TextAlign.Center)
                
                // 添加按钮 - 点击后拉起二级编辑页
                Button("添加")
                    .width('80%')
                    .type(ButtonType.Capsule)
                    .margin({ top: 20 })
                    .onClick(() => {
                        console.info(`${TAG} Button onClick`);
                        // 调用startFormEditSecondPage方法,触发startSecondPage
                        this.extensionEvent?.startFormEditSecondPage();
                    })
            }
        }
        .justifyContent(FlexAlign.Center)
        .width('100%')
    }
}

2.4 创建二级编辑页面

二级编辑页面是实际进行编辑操作的页面。这里需要创建对应的UIAbility。

// src/main/ets/formeditssecpageability/FormEditSecPageAbility.ets

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'FormEditSecPageAbility';
const DOMAIN_NUMBER: number = 0xFF00;

export default class FormEditSecPageAbility extends UIAbility {
    
    onCreate(want, launchParam) {
        hilog.info(DOMAIN_NUMBER, TAG, 'Ability onCreate');
        
        // 获取从一级编辑页传递的参数
        if (want?.parameters) {
            let params = want.parameters;
            hilog.info(DOMAIN_NUMBER, TAG, `收到参数: ${JSON.stringify(params)}`);
        }
    }
    
    onWindowStageCreate(windowStage: window.WindowStage) {
        hilog.info(DOMAIN_NUMBER, TAG, 'onWindowStageCreate');
        
        // 加载二级编辑页面
        windowStage.loadContent('pages/EditSecondPage', (err, data) => {
            if (err) {
                hilog.error(DOMAIN_NUMBER, TAG, `加载页面失败: ${JSON.stringify(err)}`);
                return;
            }
            hilog.info(DOMAIN_NUMBER, TAG, '页面加载成功');
        });
    }
}
// src/main/ets/pages/EditSecondPage.ets

@Entry
@Component
struct EditSecondPage {
    @State selectedCity: string = '北京';
    @State selectedUnit: string = '摄氏度';
    
    build() {
        Column() {
            // 标题
            Text('编辑天气卡片')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
            
            // 城市选择
            Row() {
                Text('选择城市:')
                    .fontSize(16)
                    .width(100)
                
                Picker({ selected: this.selectedCity })
                    .onChange((value: string) => {
                        this.selectedCity = value;
                    })
            }
            .margin(10)
            
            // 单位选择
            Row() {
                Text('温度单位:')
                    .fontSize(16)
                    .width(100)
                
                Radio({ value: '摄氏度', group: 'unit' })
                    .checked(this.selectedUnit === '摄氏度')
                    .onChange(() => {
                        this.selectedUnit = '摄氏度';
                    })
                Text('摄氏度')
                    .margin({ right: 20 })
                
                Radio({ value: '华氏度', group: 'unit' })
                    .checked(this.selectedUnit === '华氏度')
                    .onChange(() => {
                        this.selectedUnit = '华氏度';
                    })
                Text('华氏度')
            }
            .margin(10)
            
            // 保存按钮
            Button('保存')
                .width('80%')
                .type(ButtonType.Capsule)
                .margin({ top: 30 })
                .onClick(() => {
                    console.info(`保存设置: 城市=${this.selectedCity}, 单位=${this.selectedUnit}`);
                    // 这里调用updateForm刷新卡片
                    this.saveAndRefresh();
                })
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Start)
        .padding(20)
    }
    
    saveAndRefresh() {
        // 构建新数据
        let formData = {
            'city': this.selectedCity,
            'unit': this.selectedUnit,
            'updateTime': new Date().toLocaleString()
        };
        
        // TODO: 调用updateForm刷新卡片
        console.info('刷新卡片数据:', JSON.stringify(formData));
        
        // 返回上一页
        router.back();
    }
}

2.5 配置module.json5

module.json5中添加卡片编辑扩展能力的配置。

// src/main/module.json5
{
  "module": {
    // ... 其他配置
    "extensionAbilities": [
      // 已有的FormExtensionAbility
      {
        "name": "EntryFormAbility",
        "srcEntry": "./ets/entryformability/EntryFormAbility.ets",
        "type": "form"
      },
      // 新增的FormEditExtensionAbility
      {
        "name": "EntryFormEditAbility",
        "srcEntry": "./ets/entryformeditability/EntryFormEditAbility.ets",
        "type": "formEdit"
      }
    ],
    "abilities": [
      // 二级编辑页的UIAbility
      {
        "name": "FormEditSecPageAbility",
        "srcEntry": "./ets/formeditssecpageability/FormEditSecPageAbility.ets",
        "description": "$string:FormEditSecPageAbility_desc",
        "icon": "$media:icon",
        "label": "$string:FormEditSecPageAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background"
      }
    ]
  }
}

2.6 配置卡片form_config.json

在卡片的配置文件中添加formConfigAbility字段,指向卡片编辑扩展能力。

// resources/base/profile/form_config.json
{
  "forms": [
    {
      "name": "widget",
      "displayName": "$string:widget_display_name",
      "description": "$string:widget_desc",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      // 关键:指定卡片编辑扩展能力
      "formConfigAbility": "ability://EntryFormEditAbility",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "isDynamic": true,
      "isDefault": true,
      "updateEnabled": false,
      "defaultDimension": "2×2",
      "supportDimensions": [
        "2×2",
        "2×4",
        "4×4"
      ]
    }
  ]
}

2.7 配置页面路由

main_pages.json中注册Extension页面。

// resources/base/profile/main_pages.json
{
  "src": [
    "pages/Index",
    "pages/Extension",          // 一级编辑页
    "pages/EditSecondPage"       // 二级编辑页
  ]
}

三、流程时序图

用户                     桌面                    FormEditExtensionAbility          二级编辑页
 |                       |                                  |                          |
 | 点击卡片编辑            |                                  |                          |
 |---------------------->|                                  |                          |
 |                       | 检测到formConfigAbility配置       |                          |
 |                       |--------------------------------->|                          |
 |                       |                                  | onSessionCreate          |
 |                       |                                  |     |                    |
 |                       |                                  | 加载一级编辑页             |
 |                       |                                  |---->                    |
 |                       |                                  |    Extension.ets         |
 |                       |                                  |                          |
 |                       |                                  | 用户点击"添加"按钮         |
 |                       |                                  |<----                    |
 |                       |                                  |                          |
 |                       |                                  | startSecondPage()        |
 |                       |                                  |----|-------------------->|
 |                       |                                  |    | 拉起二级编辑页        |
 |                       |                                  |    |                    |
 |                       |                                  |    | FormEditSecPageAbility
 |                       |                                  |    |                    |
 |                       |                                  |    | 用户完成编辑          |
 |                       |                                  |    |<-------------------|
 |                       |                                  |    |                    |
 |                       |                                  |    | updateForm刷新卡片  |
 |                       |                                  |    |---->              |
 |                       |                                  |    |                    |
 | 卡片更新显示            |                                  |    |                    |
 |<----------------------|----------------------------------|----|                    |

四、说明

4.1 核心配置

配置项 位置 说明
extensionAbilities module.json5 添加type为"formEdit"的扩展能力
formConfigAbility form_config.json 指定卡片编辑扩展能力,格式为"ability://名称"

4.2 核心方法

方法 所属类 作用
onSessionCreate FormEditExtensionAbility 会话创建时回调,加载一级编辑页
startSecondPage FormEditExtensionContext 拉起二级编辑页
loadContent UIExtensionContentSession 加载一级编辑页面

4.3 数据传递

// 通过LocalStorage传递数据
let storage: LocalStorage = new LocalStorage();
storage.setOrCreate('extensionEvent', extensionEvent);
session.loadContent('pages/Extension', storage);

// 通过startSecondPage的parameters传递参数
this.context.startSecondPage({
    bundleName: bundleName,
    parameters: {
        "secPageAbilityName": secPageAbilityName,
        "formId": formId,
        "config": JSON.stringify(configData)
    }
});

五、注意事项

5.1 版本要求

特性 最低API版本
FormEditExtensionAbility API 18+

5.2 限制

限制项 说明
formConfigAbility格式 必须为"ability://扩展能力名称"
二级编辑页类型 必须是UIAbility,不能是Extension
数据持久化 编辑后的数据需要通过updateForm刷新卡片

总结

ArkTS卡片编辑的核心:

  1. 两级编辑页设计

    • 一级编辑页:FormEditExtensionAbility

    • 二级编辑页:普通UIAbility

  2. 核心流程

    • 配置formConfigAbility

    • 实现FormEditExtensionAbility

    • onSessionCreate中加载一级编辑页

    • 一级编辑页调用startSecondPage拉起二级编辑页

    • 二级编辑页完成编辑后updateForm刷新卡片

  3. 关键配置

    • module.json5中添加type为"formEdit"的扩展能力

    • form_config.json中添加formConfigAbility字段

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐