介紹
桌面卡片是比較常見的功能,本案例詳細列舉了卡片開發的大部分功能,如使用postCardAction接口快速拉起卡片提供方應用的指定UIAbility,通過message事件刷新卡片內容等,為開發者提供了卡片功能的展示。
效果圖預覽
使用說明
- 長按應用,添加卡片到桌面。
- 卡片內可滑動選擇案例,點擊可進入案例詳情。
- 部分案例無詳情頁時,點擊跳轉到首頁瀑布流。
實現思路
- 新建卡片
- 配置formconfig
- 編寫卡片UI代碼
- 觸發刷新事件
- 觸發點擊事件
實現步驟
本例涉及的關鍵特性和實現方案如下:
新建卡片。右鍵點擊entry目錄,選擇新建->Service Widget->Dynamic Widget,其中Dynamic Widget為動態卡片,Static Widget為靜態卡片。此時會生成幾個文件:配置文件
form_config.json
;卡片AbilityEntryFormAbility.ets
;卡片組件WidgetCard.ets
。新建卡片后,根據需要(如卡片大小,刷新時間,動態靜態卡片設置)配置
form_config.json
。
{
"forms": [
{
"name": "widget", // 卡片的名稱。
"displayName": "$string:widget_display_name", // 卡片的顯示名稱。
"description": "$string:widget_desc", // 卡片的描述。
"src": "./ets/widget/pages/WidgetCard.ets", // 卡片對應的UI代碼的完整路徑。
"uiSyntax": "arkts", // 卡片的類型
"window": { // 用于定義與顯示窗口相關的配置。
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto", // 卡片的主題樣式。
"isDynamic": true, // 卡片是否為動態卡片。
"isDefault": true, // 卡片是否為默認卡片。
"updateEnabled": true, // 卡片是否支持周期性刷新。
"scheduledUpdateTime": "10:30", // 卡片的定點刷新的時刻。
"updateDuration": 1, // 卡片定時刷新的更新周期,單位為30分鐘,取值為自然數。
"defaultDimension": "6*4", // 卡片的默認外觀規格。
"supportDimensions": [ // 卡片支持的外觀規格,取值范圍。
"6*4"
]
}
]
}
編寫卡片UI代碼。在主文件
WidgetCard.ets
中添加UI組件,需要注意的是:ArkTS卡片存在較多約束(如不支持導入共享包),較多邏輯不可在卡片中使用,在使用時需要根據文檔進行操作。編寫跳轉事件:當應用未被拉起時,點擊某個卡片時跳轉到具體的案例頁面。在
EntryAbility.ets
中補充邏輯:onCreate生命周期內獲取want.parameters.params判斷卡片內容的跳轉。
// EntryAbility.ets
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ...
// 桌面卡片判斷跳轉內容
if (want?.parameters?.params) {
// want.parameters.params 對應 postCardAction() 中 params 內容
let params: Record<string, Object> = JSON.parse(want.parameters.params as string);
this.selectPage = params.targetPage as string;
}
// ...
}
}
- 編寫跳轉事件:當應用在后臺時,點擊某個卡片時跳轉到具體的案例頁面。可從onNewWant生命周期獲取want.parameters.params判斷卡片內容的跳轉。
// EntryAbility.ets
export default class EntryAbility extends UIAbility {
// 如果UIAbility已在后臺運行,在收到Router事件后會觸發onNewWant生命周期回調
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (want?.parameters?.params) {
// want.parameters.params 對應 postCardAction() 中 params 內容
let params: Record<string, Object> = JSON.parse(want.parameters.params as string);
this.selectPage = params.targetPage as string;
} else {
this.selectPage = '';
}
if (this.currentWindowStage !== null) {
// 存在窗口時點擊卡片后進行頁面跳轉
if (this.selectPage) {
waterFlowData.forEach((item: SceneModuleInfo) => {
let index = item.appUri.indexOf(this.selectPage);
if (index > -1) {
if (DynamicsRouter.appRouterStack.slice(-1)[0].name !== item.appUri) {
DynamicsRouter.clear();
DynamicsRouter.pushUri(item.appUri);
}
return;
}
})
this.selectPage = '';
}
}
}
}
- 具體跳轉邏輯編寫。在onWindowStageCreate生命周期內進行具體的跳轉邏輯。
// EntryAbility.ets
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 判斷是否存在窗口可進行頁面跳轉
if (this.currentWindowStage === null) {
this.currentWindowStage = windowStage;
}
// 點擊卡片后進行頁面跳轉
if (this.selectPage) {
this.storage.setOrCreate('formNavigationRouter', this.selectPage);
windowStage.loadContent('pages/EntryView', this.storage, (err, data) => {
if (err.code) {
logger.error(DOMAIN_NUMBER.toString(), TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
logger.info(DOMAIN_NUMBER.toString(), TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
// ...
}
}
- 編寫跳轉事件:在
EntryAbility.ets
編寫事件后,同時在接收案例參數的EntryView.ets
內處理頁面跳轉邏輯。通過和DynamicsRouter內的數據對比,判斷通過storage傳入的頁面是哪一個,然后執行pushUri跳轉。
@Entry(storage)
@Component
struct EntryView {
onPageShow(): void {
// 從卡片進入頁面時判斷具體跳轉頁面
if (this.formRouter) {
waterFlowData.forEach((item: SceneModuleInfo) => {
let index = item.appUri.indexOf(this.formRouter);
if (index > -1) {
if (DynamicsRouter.appRouterStack.slice(-1)[0].name !== item.appUri) {
DynamicsRouter.clear();
DynamicsRouter.pushUri(item.appUri);
}
return;
}
})
this.formRouter = '';
}
}
}
- 判斷卡片大小:獲取卡片詳情,根據寬高比獲取卡片的規格,不同規格顯示內容不同。在
EntryFormAbility.ets
中補充點擊卡片進入時查找對應案例的邏輯。在onAddForm生命周期內做卡片生成時,createFormBindingData方法傳遞屬性。
// EntryFormAbility.ets
export default class EntryFormAbility extends FormExtensionAbility {
// 卡片對象集合
onAddForm(want: Want): formBindingData.FormBindingData {
let isLongCard: boolean = true;
if ((want.parameters?.[formInfo.FormParam.WIDTH_KEY] as number) /
(want.parameters?.[formInfo.FormParam.HEIGHT_KEY] as number) > 0.666) {
isLongCard = false;
}
// 使用方創建卡片時觸發,提供方需要返回卡片數據綁定類
let obj: Record<string, string | boolean> = {
'title': 'titleOnAddForm',
'isLongCard': isLongCard
};
let formData: formBindingData.FormBindingData = formBindingData.createFormBindingData(obj);
return formData;
}
}
- 編寫刷新事件:當定時更新或定點更新觸發時,需要更新卡片內容。onUpdateForm生命周期發生在定時更新/定點更新/卡片使用方主動請求更新時,在方法內增加獲取案例數據的功能。
// EntryFormAbility.ets
export default class EntryFormAbility extends FormExtensionAbility {
// 網絡獲取README數據并利用formProvider.updateForm更新到卡片
async getData(formId: string) {
let detail: CASES[] = [];
let httpRequest = http.createHttp();
let webData: http.HttpResponse = await httpRequest.request(URL);
if (webData?.responseCode == http.ResponseCode.OK) {
try {
detail = this.formatData(webData.result.toString());
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent' + 'webData.result:' + webData.result);
class FormDataClass {
detail: CASES[] = detail;
}
let formData = new FormDataClass();
let formInfo = formBindingData.createFormBindingData(formData);
await formProvider.updateForm(formId, formInfo);
hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'FormAbility updateForm success.');
} catch (error) {
hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`);
}
} else {
hilog.error(DOMAIN_NUMBER, TAG, `ArkTSCard download task failed`);
let param: Record<string, string> = {
'text': '刷新失敗'
};
let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param);
formProvider.updateForm(formId, formInfo);
}
httpRequest.destroy();
}
async onUpdateForm(formId: string): Promise<void> {
// 若卡片支持定時更新/定點更新/卡片使用方主動請求更新功能,則提供方需要重寫該方法以支持數據更新
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm');
this.getData(formId);
}
}
- 編寫刷新事件:手動刷新內容時,需要更新卡片內容。onFormEvent生命周期發生在卡片主動通過postCardAction接口觸發message事件。
// EntryFormAbility.ets
export default class EntryFormAbility extends FormExtensionAbility {
// 網絡獲取README數據并利用formProvider.updateForm更新到卡片
async getData(formId: string) {
let detail: CASES[] = [];
let httpRequest = http.createHttp();
let webData: http.HttpResponse = await httpRequest.request(URL);
if (webData?.responseCode == http.ResponseCode.OK) {
try {
detail = this.formatData(webData.result.toString());
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onFormEvent' + 'webData.result:' + webData.result);
class FormDataClass {
detail: CASES[] = detail;
}
let formData = new FormDataClass();
let formInfo = formBindingData.createFormBindingData(formData);
await formProvider.updateForm(formId, formInfo);
hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'FormAbility updateForm success.');
} catch (error) {
hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`);
}
} else {
hilog.error(DOMAIN_NUMBER, TAG, `ArkTSCard download task failed`);
let param: Record<string, string> = {
'text': '刷新失敗'
};
let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param);
formProvider.updateForm(formId, formInfo);
}
httpRequest.destroy();
}
async onFormEvent(formId: string, message: string): Promise<void> {
this.getData(formId);
}
}
- 編寫刷新事件:參數傳到卡片組件內,組件接收參數。處理
WidgetCard.ets
卡片內邏輯。卡片頁面中使用LocalStorageProp裝飾需要刷新的卡片數據。
let casesCardInfo = new LocalStorage();
@Entry(casesCardInfo)
@Component
struct Widget_DynamicCard {
@LocalStorageProp('detail') detail: CASES[] = []; // 卡片對象集合
private swiperController: SwiperController = new SwiperController();
@LocalStorageProp('isLongCard') isLongCard: boolean = false;
build() {
// ...
}
}
寫在最后
- 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
- 關注小編,同時可以期待后續文章ing??,不定期分享原創知識。
- 想要獲取更多完整鴻蒙最新學習知識點,請移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu