鸿蒙卡片开发保姆级教程

卡片

1. 卡片概念

  1. 什么是卡片? 卡片用来显示或者提示一些基本信息或者进行一些基本操作。注意不能做重逻辑,所有重要逻辑全部交给应用
  2. 如果是元服务如何唤醒? 因为元服务不提供桌面应用图标,我们可以通过用户手动的方式在桌面上添加一张卡片,通过点击卡片来唤起元服务。

2. 创建卡片

  1. 在编辑器中创建

  2. 选择动态卡片




    卡片的特点
    1.卡片只能承载少量的内容和交互
    2. 卡片可以充当元服务icon作为入口,默认提供一张服务卡片作为入口
    3. 普通应用也可以添加服务卡片,但默认没有添加卡片

    元服务和普通应用的区别

  3. 添加卡片

3. ArkTS卡片实现原理

4. ArkTS卡片渲染服务运行原理

5. 卡片的服务通信

5.1 卡片-------> 应用
  • 使用postCardAction方法
  1. 在卡片pages中书写代码
typescript 复制代码
// 卡片的应用
@Entry
@Component
struct WidgetCard {
  @State count: number = 10;
  build() {
    Column() {
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;

            postCardAction(this, {
              action: 'call',
              abilityName: 'EntryAbility',
              params: {
                method: 'updateFormCount',
                num: this.count
              }
            })
          })

        Text(this.count.toString())
          .fontSize(18)

        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
              postCardAction(this,{
                action:'call',
                abilityName: 'EntryAbility',
                params:{
                  method:'updateFormCount',
                  num:this.count
                }
              })
            }
          })
      }
    }
    .width('100%')
    .height('100%')
    .onClick(() => {
    	// 点击唤醒应用
      postCardAction(this, {
        action: 'router',
        abilityName: 'EntryAbility'
      })
    })
  }
}
  1. module.json5添加-保持应用在后台权限
typescript 复制代码
 "requestPermissions": [{
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
    }],
  1. 应用的entryability中进行接收
typescript 复制代码
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { rpc } from '@kit.IPCKit';
import { JSON } from '@kit.ArkTS';
import { preferences } from '@kit.ArkData';
import { formBindingData, formProvider } from '@kit.FormKit';

const DOMAIN = 0x0000;

//必须是rpc.Parcelable类型
class Params implements rpc.Parcelable {
  marshalling(dataOut: rpc.MessageSequence): boolean {
    return true;
  }

  unmarshalling(dataIn: rpc.MessageSequence): boolean {
    return true;
  }
}

class CardParams {
  count: number = 0
  formId:string = ""
}

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
    this.callee.on("updateFormCount", (data) => {
      const res = JSON.parse(data.readString()) as CardParams;
      AppStorage.setOrCreate('count', res.count);


	//必须返回一个rpc.Parcelable类型
      return new Params();
    })
  }

  onDestroy(): void {
  	//销毁时解除监听
    this.callee.off("updateFormCount")
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}
  1. 主页Index.ets
typescript 复制代码
import { preferences } from '@kit.ArkData'
import { formBindingData, formProvider } from '@kit.FormKit'

@Component
@Entry
struct Index {
  @StorageLink('count')
  count:number = 0
  build() {
    Column(){
      Text('课程太多了')
        .fontSize(18)
        .fontColor(Color.Orange)
        .fontWeight(700)
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;
          })

        Text(this.count.toString())
          .fontSize(18)

        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
            }
          })
      }
    }
    .backgroundColor(Color.Pink)
    .width('100%')
    .height('100%')
  }
}

总结:如图示

5.2 应用----------->卡片
  1. 卡片的ability的entryformability的onAddForm方法中添加
typescript 复制代码
onAddForm(want: Want) {
    // Called to return a FormBindingData object.
    return formBindingData.createFormBindingData({
      formId: want.parameters!["ohos.extra.param.key.form_identity"] as string
    });
  }
  1. 卡片:WidgetCard.ets 监听formId ,当formId发生变化时,发送至应用
typescript 复制代码
 @LocalStorageProp("formId")
  @Watch("updateFormId")
  formId: string = ""

  updateFormId () {
    postCardAction(this, {
      action: 'call',
      abilityName: 'EntryAbility', // 只能跳转到当前应用下的UIAbility
      params: {
        method: 'updateFormId',
        formId: this.formId
      }
    })
  }
  1. 在ability中通过callee监听方法,将formId存入持久化
typescript 复制代码
 this.callee.on("updateFormId", (data) => {
      const res = JSON.parse(data.readString()) as CardParams
      const store = preferences.getPreferencesSync(this.context, {
        name: 'formIdList'
      })
      const list = JSON.parse(store.getSync("formIdList", "[]") as string) as string[]
      if(!list.includes(res.formId)) {
        list.push(res.formId)
      }
      store.putSync("formIdList", JSON.stringify(list))
      store.flush()
      formProvider.updateForm(res.formId, formBindingData.createFormBindingData({
        num: AppStorage.get("num")
      }))
      return new Params()
    })
  1. 卸载时解除
typescript 复制代码
  onDestroy(): void {
    this.callee.off("updateNum")
    this.callee.off("updateFormId")
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }
  1. Index.ets
typescript 复制代码
@StorageLink("num")
  @Watch("pushCard")
  num: number = 0

  pushCard() {
    const store = preferences.getPreferencesSync(getContext(), {
      name: 'formIdList'
    })
    const formIdList = JSON.parse(store.getSync("formIdList", "[]") as string) as string[]
    if (formIdList && formIdList.length) {
      formIdList.forEach((formId) => {
        formProvider.updateForm(formId, formBindingData.createFormBindingData({
          num: this.num
        }))
      })

    }
  }
  1. 卡片:从推送的数据中从新获取
typescript 复制代码
@Entry
@Component
struct WidgetCard {
  //修改成@LocalStorageProp
  @LocalStorageProp("count")  
  count: number = 0;
  @LocalStorageProp("formId")
  @Watch("updateFormId")
  formId:string = ""
  //应用===》卡片  需要把formId给到应用
  updateFormId(){
    postCardAction(this,{
      action:'call',
      abilityName: 'EntryAbility',
        params:{
          method:'updateFormId',
          formId:this.formId
        }
    })
  }

  build() {
    Column() {
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;

            postCardAction(this, {
              action: 'call',
              abilityName: 'EntryAbility',
              params: {
                method: 'updateFormCount',
                count: this.count
              }
            })
          })

        Text(this.count.toString())
          .fontSize(18)
        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
              postCardAction(this,{
                action:'call',
                abilityName: 'EntryAbility',
                params:{
                  method:'updateFormCount',
                  count:this.count
                }
              })
            }
          })
      }
    }
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .width('100%')
    .height('100%')
    .onClick(() => {
      postCardAction(this, {
        action: 'router',
        abilityName: 'EntryAbility'
      })
    })
  }
}

总结:如图示:

相关推荐
qq_177767371 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767371 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
烬头88212 小时前
React Native鸿蒙跨平台采用了函数式组件的形式,通过 props 接收分类数据,使用 TouchableOpacity实现了点击交互效果
javascript·react native·react.js·ecmascript·交互·harmonyos
qq_177767372 小时前
React Native鸿蒙跨平台通过Animated.Value.interpolate实现滚动距离到动画属性的映射
javascript·react native·react.js·harmonyos
qq_177767373 小时前
React Native鸿蒙跨平台实现消息列表用于存储所有消息数据,筛选状态用于控制消息筛选结果
javascript·react native·react.js·ecmascript·harmonyos
ujainu4 小时前
Flutter + OpenHarmony 实战:从零开发小游戏(三)——CustomPainter 实现拖尾与相机跟随
flutter·游戏·harmonyos
程序员清洒4 小时前
Flutter for OpenHarmony:Scaffold 与 AppBar — 应用基础结构搭建
flutter·华为·鸿蒙
拉轰小郑郑5 小时前
鸿蒙ArkTS中Object类型与类型断言的理解
华为·harmonyos·arkts·openharmony·object·类型断言
2601_949593655 小时前
基础入门 React Native 鸿蒙跨平台开发:Animated 动画按钮组件 鸿蒙实战
react native·react.js·harmonyos
菜鸟小芯5 小时前
【开源鸿蒙跨平台开发先锋训练营】DAY8~DAY13 底部选项卡&推荐功能实现
flutter·harmonyos