鴻蒙HarmonyOS實戰-Stage模型(卡片資料互動)

蜀道山QAQ發表於2024-05-21

🚀一、卡片資料互動

HarmonyOS卡片資料互動是指在基於鴻蒙作業系統的裝置上,卡片介面之間進行資料的傳輸和互動。

HarmonyOS的卡片是一種輕量級的應用介面,可以在裝置的螢幕上顯示資訊和提供操作功能。卡片可以包含各種型別的內容,如文字、圖片、按鈕、輸入框等,並可以根據使用者的操作進行相應的響應。卡片可以在裝置的主螢幕、通知欄、應用中心等位置顯示,使用者可以透過滑動、點選等操作與卡片進行互動。

在HarmonyOS中,卡片之間可以透過資料互動來實現資訊的共享和傳遞。例如,一個音樂播放器的卡片可以將當前播放的歌曲和進度資訊共享給其他卡片,實現多個卡片之間的同步。另外,卡片還可以透過資料互動來獲取其他卡片的資訊,從而實現卡片之間的互動和聯動。

HarmonyOS提供了一套豐富的API和框架來支援卡片之間的資料互動,開發者可以使用這些工具來實現卡片之間的資料共享和互動功能。透過卡片資料互動,使用者可以方便地在各個卡片之間切換和操作,提升了使用者體驗和裝置的智慧化程度。

🔎1.卡片資料互動說明

ArkTS卡片框架提供了updateForm()介面和requestForm()介面來主動觸發卡片的頁面重新整理。

updateForm()介面用於更新卡片的表單資料,當卡片的某些資料發生變化時,可以呼叫該介面將最新的資料傳遞給卡片,從而更新卡片的顯示內容。

requestForm()介面用於請求重新載入卡片的表單資料,當需要更新卡片的顯示內容時,可以呼叫該介面觸發卡片重新載入資料並重新整理頁面。

這兩個介面可以根據業務需求靈活使用,使得卡片能夠根據最新的資料進行動態更新,提供更好的使用者體驗。

🔎2.定時重新整理和定點重新整理

HarmonyOS卡片框架提供了定時重新整理和定點重新整理的功能,以便實現動態更新卡片的顯示內容。

定時重新整理是指卡片可以按照預設的時間間隔進行自動重新整理。這樣可以保持卡片的顯示內容與後臺資料的同步,實現實時的資料展示。開發者可以使用定時器或者系統提供的定時任務功能來實現定時重新整理。

定點重新整理是指卡片可以根據特定的事件或者條件觸發重新整理。例如,當某個操作完成時,可以觸發卡片重新整理以顯示最新的結果。開發者可以在相應的事件或條件觸發時,呼叫卡片框架提供的重新整理介面,來實現定點重新整理。

透過定時重新整理和定點重新整理,開發者可以根據實際需求來控制卡片的重新整理頻率和時機,從而提供更好的使用者體驗。

🦋2.1 定時重新整理

{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true, // 使能重新整理功能
      "scheduledUpdateTime": "10:30",                               
      "updateDuration": 2, // 設定卡片定時重新整理的更新週期(單位為30分鐘,取值為自然數)
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}

image

🦋2.2 定點重新整理

{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true, // 使能重新整理功能
      "scheduledUpdateTime": "10:30", // 設定卡片的定點重新整理的時刻
      "updateDuration": 0,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}

image

🦋2.3 下次重新整理

import formProvider from '@ohos.app.form.formProvider';

let formId = '123456789'; // 實際業務場景需要使用正確的formId
try {
  // 設定過5分鐘後更新卡片內容
  formProvider.setFormNextRefreshTime(formId, 5, (err, data) => {
    if (err) {
      console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
      return;
    } else {
      console.info('Succeeded in setFormNextRefreshTimeing.');
    }
  });
} catch (err) {
  console.error(`Failed to setFormNextRefreshTime. Code: ${err.code}, message: ${err.message}`);
}

具體重新整理可參考上篇文章

🔎3.重新整理本地圖片和網路圖片

在HarmonyOS卡片開發中,可以透過請求本地圖片和網路圖片來實現對圖片的顯示。

請求本地圖片可以使用HarmonyOS提供的資源管理器來獲取本地圖片的資源,然後將其顯示在卡片上。

先需要開啟這個許可權:

ohos.permission.INTERNET

🦋3.1 傳送本地圖片

import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';

export default class EntryFormAbility extends FormExtensionAbility {
  ...
  // 在新增卡片時,開啟一個本地圖片並將圖片內容傳遞給卡片頁面顯示
  onAddForm(want) {
    // 假設在當前卡片應用的tmp目錄下有一個本地圖片:head.PNG
    let tempDir = this.context.getApplicationContext().tempDir;
    // 開啟本地圖片並獲取其開啟後的fd
    let file;
    try {
      file = fs.openSync(tempDir + '/' + 'head.PNG');
    } catch (e) {
      console.error(`openSync failed: ${JSON.stringify(e)}`);
    }
    let formData = {
      'text': 'Image: Bear',
      'imgName': 'imgBear',
      'formImages': {
        'imgBear': file.fd
      },
      'loaded': true
    }
    // 將fd封裝在formData中並返回至卡片頁面
    return formBindingData.createFormBindingData(formData);
  }

  ...
}

🦋3.2 傳送網路片

import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import request from '@ohos.request';
import fs from '@ohos.file.fs';

export default class EntryFormAbility extends FormExtensionAbility {
  // 在卡片頁面觸發message事件時,下載一個網路圖片,並將網路圖片內容傳遞給卡片頁面顯示
  onFormEvent(formId, message) {
    let formInfo = formBindingData.createFormBindingData({
      'text': '重新整理中...'
    })
    formProvider.updateForm(formId, formInfo)
    // 注意:FormExtensionAbility在觸發生命週期回撥時被拉起,僅能在後臺存在5秒
    // 建議下載能快速下載完成的小檔案,如在5秒內未下載完成,則此次網路圖片無法重新整理至卡片頁面上
    let netFile = 'https://xxxx/xxxx.png'; // 需要在此處使用真實的網路圖片下載連結
    let tempDir = this.context.getApplicationContext().tempDir;
    let tmpFile = tempDir + '/file' + Date.now();
    request.downloadFile(this.context, {
      url: netFile, filePath: tmpFile
    }).then((task) => {
      task.on('complete', function callback() {
        console.info('ArkTSCard download complete:' + tmpFile);
        let file;
        try {
          file = fs.openSync(tmpFile);
        } catch (e) {
          console.error(`openSync failed: ${JSON.stringify(e)}`);
        }
        let formData = {
          'text': 'Image: Https',
          'imgName': 'imgHttps',
          'formImages': {
            'imgHttps': file.fd
          },
          'loaded': true
        }
        let formInfo = formBindingData.createFormBindingData(formData)
        formProvider.updateForm(formId, formInfo).then((data) => {
          console.info('FormAbility updateForm success.' + JSON.stringify(data));
        }).catch((error) => {
          console.error('FormAbility updateForm failed: ' + JSON.stringify(error));
        })
      })
      task.on('fail', function callBack(err) {
        console.info('ArkTSCard download task failed. Cause:' + err);
        let formInfo = formBindingData.createFormBindingData({
          'text': '重新整理失敗'
        })
        formProvider.updateForm(formId, formInfo)
      });
    }).catch((err) => {
      console.error('Failed to request the download. Cause: ' + JSON.stringify(err));
    });
  }

  ...
};

🦋3.3 卡片UI接收資料

let storage = new LocalStorage();

@Entry(storage)
@Component
struct WidgetCard {
  @LocalStorageProp('text') text: string = '載入中...';
  @LocalStorageProp('loaded') loaded: boolean = false;
  @LocalStorageProp('imgName') imgName: string = 'name';

  build() {
    Column() {
      Text(this.text)
        .fontSize('12vp')
        .textAlign(TextAlign.Center)
        .width('100%')
        .height('15%')

      Row() {
        if (this.loaded) {
          Image('memory://' + this.imgName)
            .width('50%')
            .height('50%')
            .margin('5%')
        } else {
          Image('common/start.PNG')
            .width('50%')
            .height('50%')
            .margin('5%')
        }
      }.alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Center)

      Button('重新整理')
        .height('15%')
        .onClick(() => {
          postCardAction(this, {
            'action': 'message',
            'params': {
              'info': 'refreshImage'
            }
          });
        })
    }
    .width('100%').height('100%')
    .alignItems(HorizontalAlign.Center)
    .padding('5%')
  }
}

🔎4.根據卡片狀態重新整理不同內容

我們可以新增兩張桌面卡片,一張顯示杭州的天氣,另一張顯示北京的天氣。這些卡片可以在每天早上7點觸發定時重新整理。卡片需要能夠感知當前的配置是杭州還是北京,並根據情況選擇相應城市的天氣資訊進行重新整理。以下示例展示瞭如何根據卡片的狀態動態選擇需要重新整理的內容。

1、配置定時重新整理

{
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "07:00",
      "updateDuration": 0,
      "defaultDimension": "2*2",
      "supportDimensions": ["2*2"]
    }
  ]
}

2、選擇狀態

let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
  @LocalStorageProp('textA') textA: string = '待重新整理...';
  @LocalStorageProp('textB') textB: string = '待重新整理...';
  @State selectA: boolean = false;
  @State selectB: boolean = false;

  build() {
    Column() {
      Row() {
        Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
          .select(false)
          .onChange((value: boolean) => {
            this.selectA = value;
            postCardAction(this, {
              'action': 'message',
              'params': {
                'selectA': JSON.stringify(value)
              }
            });
          })
        Text('狀態A')
      }

      Row() {
        Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
          .select(false)
          .onChange((value: boolean) => {
            this.selectB = value;
            postCardAction(this, {
              'action': 'message',
              'params': {
                'selectB': JSON.stringify(value)
              }
            });
          })
        Text('狀態B')
      }

      Row() { // 選中狀態A才會進行重新整理的內容
        Text('狀態A: ')
        Text(this.textA)
      }

      Row() { // 選中狀態B才會進行重新整理的內容
        Text('狀態B: ')
        Text(this.textB)
      }
    }.padding('10%')
  }
}

3、根據狀態重新整理內容

import formInfo from '@ohos.app.form.formInfo'
import formProvider from '@ohos.app.form.formProvider';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import dataStorage from '@ohos.data.storage'

export default class EntryFormAbility extends FormExtensionAbility {
  onAddForm(want) {
    let formId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
    let isTempCard: boolean = want.parameters[formInfo.FormParam.TEMPORARY_KEY];
    if (isTempCard === false) { // 如果為常態卡片,直接進行資訊持久化
      console.info('Not temp card, init db for:' + formId);
      let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
      storeDB.putSync('A' + formId, 'false');
      storeDB.putSync('B' + formId, 'false');
      storeDB.flushSync();
    }
    let formData = {};
    return formBindingData.createFormBindingData(formData);
  }

  onRemoveForm(formId) {
    console.info('onRemoveForm, formId:' + formId);
    let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
    storeDB.deleteSync('A' + formId);
    storeDB.deleteSync('B' + formId);
  }

  // 如果在新增時為臨時卡片,則建議轉為常態卡片時進行資訊持久化
  onCastToNormalForm(formId) {
    console.info('onCastToNormalForm, formId:' + formId);
    let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
    storeDB.putSync('A' + formId, 'false');
    storeDB.putSync('B' + formId, 'false');
    storeDB.flushSync();
  }

  onUpdateForm(formId) {
    let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
    let stateA = storeDB.getSync('A' + formId, 'false').toString()
    let stateB = storeDB.getSync('B' + formId, 'false').toString()
    // A狀態選中則更新textA
    if (stateA === 'true') {
      let formInfo = formBindingData.createFormBindingData({
        'textA': 'AAA'
      })
      formProvider.updateForm(formId, formInfo)
    }
    // B狀態選中則更新textB
    if (stateB === 'true') {
      let formInfo = formBindingData.createFormBindingData({
        'textB': 'BBB'
      })
      formProvider.updateForm(formId, formInfo)
    }
  }

  onFormEvent(formId, message) {
    // 存放卡片狀態
    console.info('onFormEvent formId:' + formId + 'msg:' + message);
    let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
    let msg = JSON.parse(message)
    if (msg.selectA != undefined) {
      console.info('onFormEvent selectA info:' + msg.selectA);
      storeDB.putSync('A' + formId, msg.selectA);
    }
    if (msg.selectB != undefined) {
      console.info('onFormEvent selectB info:' + msg.selectB);
      storeDB.putSync('B' + formId, msg.selectB);
    }
    storeDB.flushSync();
  }
};

🔎5.使用方重新整理卡片內容(僅對系統應用開放)

在HarmonyOS中,要根據formId重新整理卡片內容,可以透過以下步驟實現:

首先,在需要重新整理卡片內容的地方,獲得當前的formId。

使用FormManager類的refreshForm方法重新整理卡片內容。該方法接受兩個引數,第一個引數為要重新整理的卡片的formId,第二個引數為待重新整理的資料。

在refreshForm方法中,可以更新卡片的內容,例如更新文字、圖片或其他UI元素。可以透過呼叫卡片所使用的元件的相應方法,將新資料應用到卡片中。

import formHost from '@ohos.app.form.formHost';

@Entry()
@Component
struct WidgetCard {
  formId = ...; // 卡片ID

  build() {
    Button(`重新整理卡片`)
      .type(ButtonType.Capsule)
      .width('50%')
      .height(50)
      .onClick(() => {
        console.info('FormAbility update form click');
        // formId需要為實際需要重新整理的卡片ID
        formHost.requestForm(this.formId.toString()).then(() => {
          console.info('Succeeded in requestForming.');
        });
      })

    ...
  }
}

🚀寫在最後

  • 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
  • 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  • 關注小編,同時可以期待後續文章ing🚀,不定期分享原創知識。
  • 更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

image

相關文章