HarmonyOS鸿蒙Next中卡片添加到桌面编辑
HarmonyOS鸿蒙Next中卡片添加到桌面编辑 看到一个待办卡片长按可以编辑卡片设置,是怎么实现的?比如修改卡片背景、文字大小。
可以参考桌面提供统一的卡片编辑页,卡片提供方使用卡片框架提供的FormEditExtensionAbility开发卡片编辑功能。
示例如下:
提供了卡片一级编辑页面和二级卡片编辑功能,在一级编辑页面实现修改卡片字体大小的功能。二级编辑可根据实际业务需要保留或删除。
1.在工程的entry模块中,在src/main/ets目录下新建entryformeditability文件夹。
2.在entryformeditability文件夹下,创建EntryFormEditAbility.ets文件。在EntryFormEditAbility文件中,实现startSecondPage方法,在onSessionCreate回调方法中,加载一级卡片编辑页,并将startSecondPage方法的实现传递给一级卡片编辑页。
// src/main/ets/entryformeditability/EntryFormEditAbility.ets
import { FormEditExtensionAbility } from '@kit.FormKit';
import { UIExtensionContentSession, Want } 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} EntryFormEditAbility onForeground.....`);
}
onBackground(): void {
console.info(`${TAG} EntryFormEditAbility onBackground......`);
}
onDestroy(): void {
console.info(`${TAG} EntryFormEditAbility onDestroy......`);
}
onSessionCreate(want: Want, session: UIExtensionContentSession) {
console.info(`${TAG} onSessionCreate start..... ${want.bundleName}`);
// 获取被编辑卡片的卡片ID和预览卡片的卡片ID,通过storage同步到一级编辑页中
const formId: string | undefined = want.parameters?.cardId as string;
const previewFormId: string | undefined = want.parameters?.previewCardId as string;
let storage: LocalStorage = new LocalStorage();
let extensionEvent: ExtensionEvent = new ExtensionEvent();
extensionEvent.setStartSecondPage(() => this.startSecondPage());
storage.setOrCreate('extensionEvent', extensionEvent);
// 保存
if (formId) {
console.info(`${TAG} form id is ${formId}`);
storage.setOrCreate('formId', formId);
}
if (previewFormId) {
console.info(`${TAG} preview form id is ${previewFormId}`);
storage.setOrCreate('previewFormId', previewFormId);
}
try {
session.loadContent('pages/Extension', storage);
} catch (e) {
console.error(`${TAG} EntryFormEditAbility loadContent err, want: ${JSON.stringify(e)}`);
}
}
onSessionDestroy() {
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 {
this.context.startSecondPage({
bundleName: bundleName,
parameters: {
'secPageAbilityName': secPageAbilityName
}
});
} catch (err) {
console.error(`${TAG} startSecondPage failed: ${err}`);
}
}
};
3.在entryformeditability文件夹下,创建FormEditSecPageAbility.ets文件。在onSessionCreate回调方法中,加载二级卡片编辑页。
// entry/src/main/ets/entryformeditability/FormEditSecPageAbility.ets
import { FormEditExtensionAbility } from '@kit.FormKit';
import { UIExtensionContentSession, Want } from '@kit.AbilityKit';
import { ExtensionEvent } from '../pages/model/ExtensionEvent';
const TAG: string = 'FormEditDemo[FormEditSecPageAbility] -->';
export default class FormEditSecPageAbility extends FormEditExtensionAbility {
onCreate() {
console.info(TAG, `Ability onCreate`);
}
onForeground(): void {
console.info(TAG, `Ability onForeground`);
}
onBackground(): void {
console.info(TAG, `Ability onBackground`);
}
onDestroy(): void {
console.info(TAG, `Ability onDestroy`);
}
onSessionCreate(want: Want, session: UIExtensionContentSession) {
console.info(`${TAG} onSessionCreate start..... ${want.bundleName}`);
let storage: LocalStorage = new LocalStorage();
let extensionEvent: ExtensionEvent = new ExtensionEvent();
storage.setOrCreate('extensionEvent', extensionEvent);
storage.setOrCreate('session', session);
try {
session.loadContent('pages/SecondPage', storage);
console.info(TAG, `loadContent first edit page success`);
} catch (e) {
console.error(TAG, `EntryFormEditAbility loadContent err, want: ${e?.message}`);
}
}
onSessionDestroy() {
console.info(TAG, `onSessionDestroy`);
}
};
4.在src/main/ets/pages目录下新增Extension文件,用于展示卡片一级编辑页。
// src/main/ets/pages/Extension.ets
import { ExtensionEvent } from './model/ExtensionEvent';
import { formBindingData, formProvider } from '@kit.FormKit';
const TAG: string = 'FormEditDemo[Extension] -->';
@Entry
@Component
struct Extension {
localStorage = this.getUIContext().getSharedLocalStorage();
private extensionEvent: ExtensionEvent | undefined = this.localStorage?.get<ExtensionEvent>('extensionEvent');
// 获取编辑卡片的卡片ID和预览卡片的卡片ID
private formId: string = this.localStorage?.get('formId') as string;
private previewFormId: string = this.localStorage?.get('previewFormId') as string;
fontSize: number = 0;
updateForm(fontSize: number) {
if (!this.formId && !this.previewFormId) {
return;
}
let param: Record<string, number> = {
'fontSize': fontSize
};
let obj: formBindingData.FormBindingData = formBindingData.createFormBindingData(param);
try {
// 刷新被编辑卡片的信息
formProvider.updateForm(this.formId, obj, (error: BusinessError) => {
if (error) {
console.error(TAG, `callback error, code: ${error.code}, message: ${error.message})`);
return;
}
console.info(TAG, `formProvider updateForm success`);
});
} catch (error) {
console.error(TAG, `catch error, Code: ${error.code}, Message: ${error.message}`);
}
if (!this.previewFormId) {
console.error(TAG, 'previewFormId is empty');
return;
}
try {
// 刷新预览卡片的信息
formProvider.updateForm(this.previewFormId, obj, (error: BusinessError) => {
if (error) {
console.error(TAG, `callback error, code: ${error.code}, message: ${error.message})`);
return;
}
console.info(TAG, `formProvider updateForm success`);
});
} catch (error) {
console.error(TAG, `catch error, Code: ${error.code}, Message: ${error.message}`);
}
}
build() {
Row() {
Column({ space: 10 }) {
Row() {
Text('修改字体大小:');
TextInput()
.type(InputType.Number)
.layoutWeight(1)
.onChange((value) => {
this.fontSize = Number(value);
});
}.width('100%');
Button('更新字体大小')
.width('80%')
.type(ButtonType.Capsule)
.margin({
top: 20
})
.onClick(() => {
this.updateForm(this.fontSize);
});
Button('跳转二级编辑页')
.width('80%')
.type(ButtonType.Capsule)
.margin({
top: 20
})
.onClick(() => {
console.info(`${TAG} Button onClick, ${this.extensionEvent}`);
this.extensionEvent?.startFormEditSecondPage();
});
};
}
.justifyContent(FlexAlign.Center)
.width('100%');
}
}
5.在src/main/ets/pages目录下新增SecondPage文件,用于展示卡片二级编辑页。
// src/main/ets/pages/Extension.ets
const TAG: string = 'FormEditDemo[Extension] -->';
@Entry
@Component
struct SecondPage {
message: string = '这里是二级编辑页面 UIExtension Provider';
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`);
});
};
}
.justifyContent(FlexAlign.Center)
.width('100%');
}
}
6.新建src/main/ets/pages/model目录,新增ExtensionEvent文件,使用startFormEditSecondPage方法调用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!`);
};
public setStartSecondPage(startSecondPage: () => void) {
console.info(`${TAG} setStartSecondPage`);
this.startSecondPage = startSecondPage;
}
public startFormEditSecondPage(): void {
console.info(`${TAG} startFormEditSecondPage`);
this.startSecondPage();
}
}
7.在应用的module.json5配置文件中添加卡片编辑配置信息。关注extensionAbilities部分。
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
],
},
{
"name": "EntryFormAbility",
"srcEntry": "./ets/entryformability/EntryFormAbility.ets",
"label": "$string:EntryFormAbility_label",
"description": "$string:EntryFormAbility_desc",
"type": "form",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
},
{
// 一级编辑页
"name": "EntryFormEditAbility",
"srcEntry": "./ets/entryformeditability/EntryFormEditAbility.ets",
"type": "formEdit"
},
{
// 二级编辑页
"name": "FormEditSecPageAbility",
"srcEntry": "./ets/entryformeditability/FormEditSecPageAbility.ets",
"type": "formEdit"
}
]
}
}
8.在卡片的form_config.json配置文件中添加formConfigAbility配置项信息。
{
"forms": [
{
"name": "widget",
"displayName": "$string:widget_display_name",
"description": "$string:widget_desc",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"formConfigAbility": "ability://EntryFormEditAbility",
"isDynamic": true,
"isDefault": true,
"updateEnabled": false,
"scheduledUpdateTime": "10:30",
"updateDuration": 1,
"defaultDimension": "2*2",
"supportDimensions": [
"2*2"
]
}
]
}
9.在开发视图的resource/base/profile/main_pages.json文件中,注册一级及二级编辑页面文件。
{
"src": [
"pages/Index",
"pages/Extension",
"pages/SecondPage"
]
}
- 在卡片页面接收字体大小,并修改渲染。
// src/main/ets/widget/pages/WidgetCard.ets
@Entry
@Component
struct WidgetCard {
@LocalStorageProp('fontSize') fontSize: number = 12;
build() {
Row() {
Column() {
Text('嘻嘻哈哈')
.fontSize(this.fontSize)
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.font'));
};
}
.padding(16)
.width('100%')
.height('100%');
}
}
更多关于HarmonyOS鸿蒙Next中卡片添加到桌面编辑的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,卡片添加到桌面编辑主要通过长按应用图标触发。系统会显示可用的服务卡片,用户可选择卡片样式和尺寸,然后将其拖拽至桌面任意位置。桌面进入编辑模式后,可对已添加的卡片进行移动、移除或更换样式。该功能依赖应用本身提供卡片服务。
在HarmonyOS Next中,实现卡片长按编辑功能(如修改背景、文字大小)主要依赖于ArkTS UI框架和FormExtensionAbility。以下是核心实现步骤:
-
卡片配置:在
resources/base/profile/form_config.json中声明卡片支持updateEnabled能力,允许动态更新。 -
数据交互:通过
FormProvider的updateForm方法,在卡片与宿主(如桌面)间传递更新数据。长按编辑时,宿主可触发更新请求。 -
UI动态更新:在卡片的ArkUI组件中,使用状态变量(如
@State)绑定样式属性(背景色、字体大小)。当收到更新数据时,修改状态变量即可实时刷新卡片样式。 -
编辑界面:通常由宿主应用提供编辑弹窗或页面,用户修改配置后,将新配置(如
backgroundColor: '#FFEFDB', fontSize: 18)通过updateForm推送给卡片。
关键代码示例(卡片组件内):
@State bgColor: string = '#FFFFFF'
@State textSize: number = 16
build() {
Column() {
Text('待办事项')
.fontSize(this.textSize)
}
.width('100%')
.height('100%')
.backgroundColor(this.bgColor)
}
当宿主调用更新时,卡片通过onUpdateForm回调接收新配置并更新状态变量,UI自动重绘。
此机制实现了卡片样式的动态化,无需重新创建卡片即可响应编辑操作。

