HarmonyOS鸿蒙Next中如何使用卡片能力去切换图片
HarmonyOS鸿蒙Next中如何使用卡片能力去切换图片
如何使用卡片能力去切换图片
开发者您好,可查看如下方案,实现在卡片中切换展示网络图片:
【解决方案】
由于ArkTS卡片不支持直接使用网络相关路径,如果需要在卡片上展示网络图片,则需要先将网络图片下载至本地沙箱,然后Image组件通过入参(memory://fileName)中的(memory://)标识来进行远端内存图片显示。下载网络图片需要使用网络能力,申请ohos.permission.INTERNET权限,配置方式为在module.json5配置文件的requestPermissions标签中声明权限。
不同场景均需要通过httpRequest.request方法下载网络资源,在下载完成的回调中调用updateForm接口更新切换图片数据。
不同场景的区别在于下载网络图片的时机。具体来说:
场景一:主应用内主动刷新切换卡片中网络图片。
已上桌的卡片,在主应用内可通过formProvider.getPublishedRunningFormInfos接口获取所有已加桌的卡片信息。接着,通过卡片名称可以过滤出需要更新的目标卡片信息。最后下载网络图片到本地,通过updateForm接口更新卡片的图片。示例代码为:
import { formBindingData, formInfo, formProvider } from '[@kit](/user/kit).FormKit';
import { common } from '[@kit](/user/kit).AbilityKit';
import { http } from '[@kit](/user/kit).NetworkKit';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
class FormDataClass {
// 卡片需要显示图片场景,必须和下列字段formImages中的key相同
imgName: string = '';
// 卡片需要显示图片场景,必填字段(formImages不可缺省或改名),fileName对应fd
formImages: Record<string, number> = {};
}
@Component
@Entry
struct Index {
// 下载文件
download(context: Context, formId: string) {
let netFile = 'XXX'; // 网络图片地址
let httpRequest = http.createHttp();
let tempDir = context.getApplicationContext().tempDir;
let fileName = 'file' + Date.now();
let tmpFile = tempDir + '/' + fileName;
let imgFile = undefined;
let imgMap: Record<string, number> = {};
// 下载网络资源
httpRequest.request(netFile).then((data) => {
if (data?.responseCode === http.ResponseCode.OK) {
try {
let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
imgMap[fileName] = imgFile.fd;
try {
fileIo.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen) => {
console.info('write data to file succeed and size is:' + writeLen);
try {
let formData: FormDataClass = {
imgName: fileName,
formImages: imgMap
};
const formInfo = formBindingData.createFormBindingData(formData);
formProvider.updateForm(formId, formInfo).then(() => {
console.info('FormAbility updateForm success.');
}).catch((e: BusinessError) => {
console.error(`FormAbility updateForm failed: 63 ${JSON.stringify(e)}`);
});
} catch (error) {
console.error(`FormAbility updateForm failed: ${JSON.stringify(error)}`);
}
});
} catch (err) {
console.error('write data to file failed with error message: ' + err.message + ', error code: ' + err.code);
}
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e as BusinessError)}`);
} finally {
// 在fileIo.closeSync执行之前,确保formProvider.updateForm已执行完毕。
fileIo.closeSync(imgFile);
}
} else {
console.error(`ArkTSCard download task failed`);
let param: Record<string, string> = {
'text': '刷新失败'
};
const formInfo = (formBindingData.createFormBindingData(param));
formProvider.updateForm(formId, formInfo);
}
httpRequest.destroy();
});
}
build() {
Column() {
Button('更新桌面网络图片').onClick(async () => {
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
// 获取上已上桌的卡片
try {
formProvider.getPublishedRunningFormInfos().then((data: formInfo.RunningFormInfo[]) => {
console.info(`formProvider getPublishedRunningFormInfos, data: ${JSON.stringify(data)}`);
data.forEach((form) => {
let formId = form.formId;
// 可根据名称作为条件进行过滤
this.download(context, formId);
});
}).catch((error: BusinessError) => {
console.error(`promise error, code: ${error.code}, message: ${error.message})`);
});
} catch (error) {
console.error(`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message})`);
}
});
}
.width('100%')
.height('100%');
}
}
在WidgetCard卡片页面中使用LocalStorageProp装饰需要刷新切换的卡片数据,使用Image组件加载远端内存图片。示例代码为:
@Entry
@Component
struct WidgetCard {
@LocalStorageProp('imgName') imgName: string = '';
build() {
Column() {
Image('memory://' + this.imgName)
.width(100);
}
.width('100%')
.height('100%');
}
}
场景二:卡片主动刷新切换网络图片。
已上桌的卡片,在卡片可以通过postCardAction接口触发message事件拉起FormExtensionAbility,通过onFormEvent接口回调通知,以完成点击卡片控件后刷新卡片中图片的功能。值得注意的是,postCardAction操作需要配置卡片为动态卡片。详细步骤为:
- 在卡片页面通过注册Button的onClick点击事件回调,并在回调中调用postCardAction接口触发message事件。
@Entry
@Component
struct WidgetCard {
@LocalStorageProp('imgName') imgName: string = '';
build() {
Column() {
Button('更新图片').onClick(() => {
postCardAction(this, {
action: 'message',
params: { msgTest: 'messageEvent' }
});
});
Image('memory://' + this.imgName)
.width(100);
}
.width('100%')
.height('100%');
}
}
- 在FormExtensionAbility的onFormEvent生命周期中下载网络资源。
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '[@kit](/user/kit).FormKit';
import { Want } from '[@kit](/user/kit).AbilityKit';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
import { http } from '[@kit](/user/kit).NetworkKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
class FormDataClass {
// 卡片需要显示图片场景,必须和下列字段formImages中的key相同
imgName: string = '';
// 卡片需要显示图片场景,必填字段(formImages不可缺省或改名),fileName对应fd
formImages: Record<string, number> = {};
}
export default class EntryFormAbility extends FormExtensionAbility {
// 下载文件
download(context: Context, formId: string) {
let netFile = 'XXX'; // 网络图片地址
let httpRequest = http.createHttp();
let tempDir = context.getApplicationContext().tempDir;
let fileName = 'file' + Date.now();
let tmpFile = tempDir + '/' + fileName;
let imgFile = undefined;
let imgMap: Record<string, number> = {};
// 下载网络资源
httpRequest.request(netFile).then((data) => {
if (data?.responseCode === http.ResponseCode.OK) {
try {
let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
imgMap[fileName] = imgFile.fd;
try {
fileIo.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen) => {
console.info('write data to file succeed and size is:' + writeLen);
try {
let formData: FormDataClass = {
imgName: fileName,
formImages: imgMap
};
const formInfo = formBindingData.createFormBindingData(formData);
formProvider.updateForm(formId, formInfo).then(() => {
console.info('FormAbility updateForm success.');
}).catch((e: BusinessError) => {
console.error(`FormAbility updateForm failed: 63 ${JSON.stringify(e)}`);
});
} catch (error) {
console.error(`FormAbility updateForm failed: ${JSON.stringify(error)}`);
}
});
} catch (err) {
console.error('write data to file failed with error message: ' + err.message + ', error code: ' + err.code);
}
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e as BusinessError)}`);
} finally {
// 在fileIo.closeSync执行之前,确保formProvider.updateForm已执行完毕。
fileIo.closeSync(imgFile);
}
} else {
console.error(`ArkTSCard download task failed`);
let param: Record<string, string> = {
'text': '刷新失败'
};
const formInfo = (formBindingData.createFormBindingData(param));
formProvider.updateForm(formId, formInfo);
}
httpRequest.destroy();
});
}
onAddForm(want: Want) {
// Called to return a FormBindingData object.
let formId = want?.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string;
console.info('onAddForm', formId);
const formData = '';
return formBindingData.createFormBindingData(formData);
}
onCastToNormalForm(formId: string) {
// Called when the form provider is notified that a temporary form is successfully
// converted to a normal form.
console.info('onCastToNormalForm', formId);
}
onUpdateForm(formId: string) {
// Called to notify the form provider to update a specified form.
console.info('onUpdateForm', formId);
}
onFormEvent(formId: string, message: string) {
// Called when a specified message event defined by the form provider is triggered.
console.info('onFormEvent', formId, message);
this.download(this.context, formId);
}
onRemoveForm(formId: string) {
// Called to notify the form provider that a specified form has been destroyed.
console.info('onRemoveForm', formId);
}
onAcquireFormState(want: Want) {
// Called to return a {@link FormState} object.
console.info('onAcquireFormState', want.bundleName);
return formInfo.FormState.READY;
}
};
场景三:定时/定点被动刷新切换网络图片。
已上桌的卡片,可以在form_config.json配置文件的updateDuration字段中配置定时刷新间隔,也可以配置scheduledUpdateTime字段设置卡片定点刷新时间。在触发定点刷新后,系统会调用FormExtensionAbility的onUpdateForm生命周期回调,在回调中,通过updateForm接口更新卡片的图片。以卡片定点刷新为例,详细步骤为:
-
在form_config.json配置文件设置scheduledUpdateTime卡片定点刷新时间。
-
在FormExtensionAbility的onUpdateForm生命周期中下载网络资源。
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '[@kit](/user/kit).FormKit';
import { Want } from '[@kit](/user/kit).AbilityKit';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
import { http } from '[@kit](/user/kit).NetworkKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
class FormDataClass {
// 卡片需要显示图片场景,必须和下列字段formImages中的key相同
imgName: string = '';
// 卡片需要显示图片场景,必填字段(formImages不可缺省或改名),fileName对应fd
formImages: Record<string, number> = {};
}
export default class EntryFormAbility extends FormExtensionAbility {
// 下载文件
download(context: Context, formId: string) {
let netFile = 'XXX'; // 网络图片地址
let httpRequest = http.createHttp();
let tempDir = context.getApplicationContext().tempDir;
let fileName = 'file' + Date.now();
let tmpFile = tempDir + '/' + fileName;
let imgFile = undefined;
let imgMap: Record<string, number> = {};
// 下载网络资源
httpRequest.request(netFile).then((data) => {
if (data?.responseCode === http.ResponseCode.OK) {
try {
let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
imgMap[fileName] = imgFile.fd;
try {
fileIo.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen) => {
console.info('write data to file succeed and size is:' + writeLen);
try {
let formData: FormDataClass = {
imgName: fileName,
formImages: imgMap
};
const formInfo = formBindingData.createFormBindingData(formData);
formProvider.updateForm(formId, formInfo).then(() => {
console.info('FormAbility updateForm success.');
}).catch((e: BusinessError) => {
console.error(`FormAbility updateForm failed: 63 ${JSON.stringify(e)}`);
});
} catch (error) {
console.error(`FormAbility updateForm failed: ${JSON.stringify(error)}`);
}
});
} catch (err) {
console.error('write data to file failed with error message: ' + err.message + ', error code: ' + err.code);
}
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e as BusinessError)}`);
} finally {
// 在fileIo.closeSync执行之前,确保formProvider.updateForm已执行完毕。
fileIo.closeSync(imgFile);
}
} else {
console.error(`ArkTSCard download task failed`);
let param: Record<string, string> = {
'text': '刷新失败'
};
const formInfo = (formBindingData.createFormBindingData(param));
formProvider.updateForm(formId, formInfo);
}
httpRequest.destroy();
});
}
onAddForm(want: Want) {
// Called to return a FormBindingData object.
let formId = want?.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string;
console.info('onAddForm', formId);
const formData = '';
return formBindingData.createFormBindingData(formData);
}
onCastToNormalForm(formId: string) {
// Called when the form provider is notified that a temporary form is successfully
// converted to a normal form.
console.info('onCastToNormalForm', formId);
}
onUpdateForm(formId: string) {
// Called to notify the form provider to update a specified form.
console.info('onUpdateForm', formId);
this.download(this.context, formId);
}
onFormEvent(formId: string, message: string) {
// Called when a specified message event defined by the form provider is triggered.
console.info('onFormEvent', formId, message);
}
onRemoveForm(formId: string) {
// Called to notify the form provider that a specified form has been destroyed.
console.info('onRemoveForm', formId);
}
onAcquireFormState(want: Want) {
// Called to return a {@link Form更多关于HarmonyOS鸿蒙Next中如何使用卡片能力去切换图片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,使用卡片切换图片主要依赖ArkUI的声明式UI和状态管理。在卡片的build函数内,使用Image组件并绑定其src属性到一个状态变量(例如使用@State装饰的变量)。通过改变该状态变量的值(如点击按钮触发事件回调),即可动态更新卡片上显示的图片。图片资源需预先放入resources目录中引用,或使用网络图片URL。
在HarmonyOS Next中,使用卡片能力切换图片主要依赖于ArkUI的声明式开发范式与状态管理。核心是通过@State装饰器管理图片资源状态,并在卡片布局中绑定点击等事件来更新该状态。
关键步骤如下:
-
定义状态变量:使用
@State装饰器定义一个变量来存储当前显示的图片资源ID(Resource类型)。例如:@State currentImage: Resource = $r('app.media.image1') -
构建卡片UI:在自定义卡片的
build函数中,使用Image组件显示状态变量currentImage。同时,可以添加一个按钮(如Button)或为Image组件本身设置点击事件(onClick)来触发切换。build() { Column() { // 显示当前图片 Image(this.currentImage) .width('100%') .height(200) // 切换按钮 Button('切换图片') .onClick(() => { this.changeImage() }) } } -
实现切换逻辑:在点击事件的处理函数(例如
changeImage)中,更新@State变量。系统会自动检测状态变化并刷新UI。changeImage() { // 示例:在两张图片间轮换 if (this.currentImage.id === $r('app.media.image1').id) { this.currentImage = $r('app.media.image2') } else { this.currentImage = $r('app.media.image1') } }
要点说明:
- 状态驱动UI:
@State修饰的变量是响应式的。当其值改变时,所有依赖它的UI组件(本例中的Image)会自动更新。 - 资源访问:使用
$r('app.media.xxx')语法引用resources/base/media/目录下的图片资源。 - 事件交互:通过组件的
onClick事件绑定用户交互到状态变更函数。 - 卡片开发规范:需在
EntryFormAbility中创建FormBindingData来初始化卡片,并在form_config.json中配置卡片。上述UI与逻辑代码应编写在卡片的Page中。
此方法遵循HarmonyOS Next的ArkUI框架设计,通过状态管理实现了卡片内图片的动态切换。

