鸿蒙OS开发实例:【手撸服务卡片】

介绍

服务卡片指导文档位于“开发/应用模型/Stage模型开发指导/Stage模型应用组件”路径下,说明其极其重要。

本篇文章将分享实现服务卡片的过程和代码

准备

  1. 请参照[官方指导],创建一个Demo工程,选择Stage模型
鸿蒙OS开发更多内容↓点击HarmonyOS与OpenHarmony技术
鸿蒙技术文档开发知识更新库gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md在这。或+mau123789学习,是v喔

搜狗高速浏览器截图20240326151547.png

  1. 熟读HarmonyOS 官方指导 “[创建一个ArkTS卡片]”

实践总结

  1. 应用打包时,不能选择“Deploy Muti Hap Packages”方式, 否则服务卡片不会显示任何内容
  2. 官方指导中没有提示添加权限“ohos.permission.KEEP_BACKGROUND_RUNNING”,如果不添加,则无法使用call方式来刷新卡片数据
  3. 卡片首次创建时,卡片Id无法传入到卡片中,需通过延时机制,二次更新

效果

Screenshot_20231201173024131.png

卡片元素说明

  1. 卡片共有使用到了7个控件
  2. 5个Text, 1个Image,  1个Rect
  3. Text('call') :  可点击,实验call事件刷新卡片内容
  4. Text('router'): 可点击,实验router事件刷新卡片内容
  5. Text('message'): 可点击,实验message事件刷新卡片内容
  6. Rect(): 实验卡片动画效果

服务卡片教程

  1. 请完全按照“创建一个ArkTS卡片”

  2. 修改生成的卡片代码(WidgetCard.ets)

let storageCard = new LocalStorage()@Entry(storageCard)
@Component
struct WidgetCard {/** The mini title.*/readonly MINI_TITLE: string = 'Title';/** The item title.*/@LocalStorageProp('ITEM_TITLE')ITEM_TITLE: string = '标题';/** The item content.*/@LocalStorageProp('ITEM_CONTENT') ITEM_CONTENT: string = '天气不错';/** The action type.*/readonly ACTION_TYPE: string = 'router';/** The ability name.*/readonly ABILITY_NAME: string = 'EntryAbility';/** The message.*/readonly MESSAGE: string = '来自服务卡片';/** The mini display priority.*/readonly MINI_DISPLAY_PRIORITY: number = 2;/** The max line.*/readonly MAX_LINES: number = 1;/** The with percentage setting.*/readonly FULL_WIDTH_PERCENT: string = '100%';/** The height percentage setting.*/readonly FULL_HEIGHT_PERCENT: string = '100%';/** Image height percentage setting.*/readonly IMAGE_HEIGHT_PERCENT: string = '64%';@State mini: boolean = false;@State rectWidth: string = '30%'@LocalStorageProp('formId') formId: string = '0';build() {Row() {Column() {if (this.mini) {Column() {Text(this.MINI_TITLE).fontSize($r('app.float.mini_title_font_size')).fontColor($r('app.color.mini_text_font_color')).margin({left: $r('app.float.mini_title_margin'),bottom: $r('app.float.mini_title_margin')})}.width(this.FULL_WIDTH_PERCENT).alignItems(HorizontalAlign.End).backgroundImageSize(ImageSize.Cover).backgroundImage($r("app.media.ic_widget"), ImageRepeat.NoRepeat).displayPriority(this.MINI_DISPLAY_PRIORITY)}Stack(){Image($r("app.media.ic_widget")).width(this.FULL_WIDTH_PERCENT).height('100%').objectFit(ImageFit.Cover).borderRadius($r('app.float.image_border_radius'))Rect().width(this.rectWidth).height('100%').fill('#60ff0000').animation({duration: 3000,curve: Curve.Linear,playMode: PlayMode.Normal,iterations: -1,onFinish:()=>{if(this.rectWidth == '30%'){this.rectWidth = '50%'} else {this.rectWidth = '30%'}}})Row(){Column({space: 20}){Text('call').fontColor(Color.Red).onClick(()=>{console.log('formId: '+this.formId)postCardAction(this, {'action': 'call','abilityName': 'EntryAbility','params': {'method': 'funA','formId': this.formId}});})Text('router').onClick(()=>{postCardAction(this, {'action': 'router','abilityName': 'EntryAbility','params': {'msgTest': 'messageEvent'}});})}Column(){Text('message').fontColor(Color.Green).onClick(()=>{postCardAction(this, {'action': 'message','params': {'msgTest': 'messageEvent'}});})}}.height('100%')}.width(this.FULL_WIDTH_PERCENT).height(this.IMAGE_HEIGHT_PERCENT)Blank()Text(this.ITEM_TITLE).fontSize($r('app.float.normal_title_font_size'))Text(this.ITEM_CONTENT).maxLines(this.MAX_LINES).fontSize($r('app.float.normal_content_font_size')).textOverflow({ overflow: TextOverflow.Ellipsis })}.width(this.FULL_WIDTH_PERCENT).height(this.FULL_HEIGHT_PERCENT).alignItems(HorizontalAlign.Start).backgroundColor($r('app.color.start_window_background'))}.height(this.FULL_HEIGHT_PERCENT).alignItems(VerticalAlign.Top).padding($r('app.float.row_padding')).onClick(() => {postCardAction(this, {"action": this.ACTION_TYPE,"abilityName": this.ABILITY_NAME,"params": {"message": this.MESSAGE}});})}
}
  1. 修改应用入口EntryAbility.ets
import window from '@ohos.window';
import UIAbility from '@ohos.app.ability.UIAbility';
import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import formInfo from '@ohos.app.form.formInfo';export default class EntryAbility extends UIAbility {storage: LocalStorageonCreate(want, launchParam) {try{let params = JSON.parse(want.parameters.params);console.log('onCreate ' + params['message'])this.storage = new LocalStorage({'ext': params['message']})} catch (e){console.log(e)}try{// 监听call事件所需的方法this.callee.on('funA', FunACall);} catch (e){console.log(e)}if (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY];updateCardContent(curFormId, "EntryAbility", "router-welcome")}}onNewWant(want, launchParam) {try{let params = JSON.parse(want.parameters.params);console.log('onNewWant ' + params['message'])this.storage = new LocalStorage({'ext': params['message']})} catch (e){console.log(e)}}onWindowStageCreate(windowStage: window.WindowStage) {windowStage.loadContent('pages/Index', this.storage, (err, data) => {});}onDestroy(){console.log('onDestroy')// this.callee.off('funA')}}// 在收到call事件后会触发callee监听的方法
function FunACall(data) {// 获取call事件中传递的所有参数try{let params = JSON.parse(data.readString())if (params.formId !== undefined) {let curFormId = params.formId;updateCardContent(curFormId, "EntryAbility", "caller-welcome")}} catch (e){console.log(e)}return null;
}function updateCardContent(formId, method, content){let formData = {'ITEM_TITLE': method, // 和卡片布局中对应'ITEM_CONTENT': content, // 和卡片布局中对应};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));})
}
修改应用入入口页面Index.ets
let storage = new LocalStorage()@Entry(storage)
@Component
struct Page {@State message: string = 'Hello World'@LocalStorageProp('ext') extLocalStorageParms: string = '';aboutToAppear(){console.log(this.extLocalStorageParms)if(this.extLocalStorageParms){this.message = this.extLocalStorageParms}}build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}}
  1. 修改应用入入口页面Index.ets
let storage = new LocalStorage()@Entry(storage)
@Component
struct Page {@State message: string = 'Hello World'@LocalStorageProp('ext') extLocalStorageParms: string = '';aboutToAppear(){console.log(this.extLocalStorageParms)if(this.extLocalStorageParms){this.message = this.extLocalStorageParms}}build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}}
  1. 修改EntryFormAbility.ets
import formInfo from '@ohos.app.form.formInfo';
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
import formProvider from '@ohos.app.form.formProvider';export default class EntryFormAbility extends FormExtensionAbility {onAddForm(want) {// Called to return a FormBindingData object.let formId = want.parameters["ohos.extra.param.key.form_identity"];let formData: Record<string, string> = {'formId': formId};console.log('onAddForm '+formId)let data = formBindingData.createFormBindingData(formData);setTimeout(()=>{formProvider.updateForm(formId, data).then((data) => {console.info('FormAbility updateForm success.' + JSON.stringify(data));}).catch((error) => {console.error('FormAbility updateForm failed: ' + JSON.stringify(error));})}, 1500)return data}onCastToNormalForm(formId) {// Called when the form provider is notified that a temporary form is successfully// converted to a normal form.console.log('onCastToNormalForm')}onUpdateForm(formId) {// Called to notify the form provider to update a specified form.console.log('onUpdateForm')}onChangeFormVisibility(newStatus) {// Called when the form provider receives form events from the system.console.log('onChangeFormVisibility')}onFormEvent(formId, message) {// Called when a specified message event defined by the form provider is triggered.console.log(message)this.updateCardContent(formId)}onRemoveForm(formId) {// Called to notify the form provider that a specified form has been destroyed.console.log('onRemoveForm')}onAcquireFormState(want) {// Called to return a {@link FormState} object.return formInfo.FormState.READY;}updateCardContent(formId){let formData = {'ITEM_TITLE': 'EntryFormAbility', // 和卡片布局中对应'ITEM_CONTENT': 'welcome', // 和卡片布局中对应};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));})}
};
  1. 在module.json5中添加权限
"requestPermissions": [{"name":  "ohos.permission.KEEP_BACKGROUND_RUNNING","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]

 7. 最后一步,请确认你的打包方式没有选择“Deploy Multi Hap Packages”,  否则将无法看到服务卡片内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/776972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像识别在工业检测中的应用

图像识别技术在工业检测中的应用非常广泛&#xff0c;它通过自动化的图像处理和分析&#xff0c;提高了生产效率、保证了产品质量&#xff0c;并降低了人力成本。以下是图像识别在工业检测中的一些主要应用领域&#xff1a; 缺陷检测&#xff1a;在制造业中&#xff0c;图像识…

面试经典150题【111-120】

文章目录 面试经典150题【111-120】67.二进制求和190.颠倒二进制位191.位1的个数136.只出现一次的数字137.只出现一次的数字II201.数字范围按位与5.最长回文子串97.交错字符串72.编辑距离221.最大正方形 面试经典150题【111-120】 六道位运算&#xff0c;四道二维dp 67.二进制…

PCB损耗来源

信号经过PCB板会产生损耗&#xff0c;主要包括导体损耗&#xff0c;介电损耗和辐射损耗 导体损耗&#xff1a;导体损耗是由于电流流动过程中产生电阻损耗而发热。 介电损耗&#xff1a;介电损耗是由于电场通过介质时分子的交替极化和晶格碰撞造成的。 辐射损耗&#xff1a;辐…

YOLOv9 实战指南:打造个性化视觉识别利器,从零开始训练你的专属测试集

论文地址&#xff1a;YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information GitHub&#xff1a;WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information (github.com)…

定时备份mysql数据库数据--mysqldump版

前言&#xff1a;mysqldump是MySQL自带的逻辑备份工具&#xff0c;可以将整个数据库或者指定的表格导出为一个SQL脚本文件&#xff0c;可以用于数据库备份。 1、编写shell脚本 # 备份文件保存路径 backup_dir/data/mysqlbackup # 当前时间 current_timedate %Y-%m-%d-%H-%M-%S…

git 更改仓库地址

背景&#xff1a; 项目本来在A仓库进行保管&#xff0c;研发已经开发一段时间了&#xff0c;现在切换到了新的仓库B&#xff0c;研发本地如何将仓库切换到B 解决&#xff1a; # 查看远端地址 git remote -v # 查看远端仓库名 git remote # 重新设置远程仓库 git remote s…

Linux---多线程(下)

前情提要&#xff1a;Linux---多线程(上) 七、互斥 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临…

PL/SQL的词法单元

目录 字符集 标识符 分隔符 注释 oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 PL/SQL块中的每一条语句都必须以分号结束。 一个SQL语句可以跨多行&#xff0c;但分号表示该语句的结束:一行中也可以有多条 SQL语句&…

3.28(迭代搜索算法 + java学习总结)

迭代加深搜索 迭代加深算法是一在DFS的基础上添加搜索深度限制的搜索方法&#xff1b; 其核心思想是从深度为0的地方开始搜索&#xff0c;然后逐步加深搜索深度&#xff0c;重新搜索一遍&#xff1b;这对于那些已知答案在浅层&#xff0c;但整个树或图存在极多分支的情况&#…

Selenium自动化测试:从time.sleep到显式等待的转变

在自动化测试的神秘世界里&#xff0c;我们的英雄——Selenium驾驶者&#xff0c;面临着一个古老的难题&#xff1a;如何等待&#xff1f;当然&#xff0c;最简单的法术是time.sleep&#xff0c;但这就像用锤子敲打每一个螺丝——有时候行得通&#xff0c;但并不总是最好的选择…

【前端Vue】HR-saas中台项目开发md文档第1篇:vuex基础-介绍,vuex基础-初始化功能【附代码文档】

HR-saas中台管理项目开发完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;vuex基础-介绍,vuex基础-初始化功能,vuex基础-state,vuex基础-mutations,vuex基础-actions,vuex基础-getters。项目课设计&#xff0c;人力资源的环境搭建vue-element-admin的了解和…

[flask]http请求//获取请求头信息+客户端信息

在网站中查询请求头信息&#xff0c;可以通过以下操作进行 右键然后选择检查 进入改页面后选择文档&#xff0c;刷新一下页面就好了 获取所有的请求头信息 print(request.headers, type(request.headers)) 在flask模块中&#xff0c;使用上面的输出函数就可以查看到有关于请求…

Python爬虫之pyquery和parsel的使用

三、pyquery的使用 1、准备工作 pip3 install pyquery2、初始化 2.1、字符串初始化 把HTML的内容当做参数&#xff0c;来初始化PyQuery对象。 html <div><ul><li class"item-0">first item</li><li class"item-1">&l…

Qt 窗口MainWindow(上)

Qt 窗口是通过 QMainWindow 类来实现的。 QMainWindow 是一个为用户提供主窗口程序的类&#xff0c;继承自 QWidget 类&#xff0c;并且提供了⼀个预定义的布局。QMainWindow 包含一个菜单栏&#xff08;menubar&#xff09;、多个工具栏(toolbars)、多个浮动窗口&#xff08;…

第十四届蓝桥杯JavaA组省赛真题 - 特殊日期

解题思路&#xff1a; 暴力秒了 public class Main {public static void main(String[] args) {int cnt 0;for (int i 1900; i < 9999; i) {for (int j 1; j < 12; j) {for (int k 1; k < days(i, j); k) {if (sum(i) sum(j) sum(k)) cnt;}}}System.out.print…

安防监控视频汇聚平台EasyCVR启用图形验证码之后如何调用login接口?

视频综合管理平台EasyCVR视频监控系统支持多协议接入、兼容多类型设备&#xff0c;平台可以将区域内所有部署的监控设备进行统一接入与集中汇聚管理&#xff0c;实现对监控区域的实时高清视频监控、录像与存储、设备管理、云台控制、语音对讲、级联共享等&#xff0c;在监控中心…

【Vue】可拖拽侧边栏实现

在本篇博客中&#xff0c;我们将探讨如何在 Vue.js 项目中实现一个可拖拽的侧边栏。此功能可以通过修改 HTML 和 Vue 组件的脚本来实现。 首先&#xff0c;我们需要在 HTML 文件中定义侧边栏的容器和用于拖拽的元素。在 Vue 组件中&#xff0c;我们将使用 Vue 的响应式系统来追…

Android JNI开发定义全局变量

要在 C 文件中设置一个 string 类型的全局变量&#xff0c;让其他 C 文件都可以访问&#xff0c;并且可以通过 JNI 方法修改这个变量&#xff0c;可以按照以下步骤进行操作 定义全局变量&#xff1a; 在一个头文件&#xff08;比如 common.h&#xff09;中定义一个全局的 strin…

力扣73. 矩阵置零

Problem: 73. 矩阵置零 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a;利用一个等大的矩阵判定 复制一个与原始矩阵一样大的矩阵temp&#xff0c;遍历temp时若temp[i][j] 0&#xff0c;则将martix对应的行与列均设置为0 思路2&#xff1a;利用两个一维矩阵…

【Linux】UnixBench介绍、分数调优思路以及测试2D3D的方法

一.简介 unixbench是一个用于测试unix系统性能的工具&#xff0c;也是一个比较通用的benchmark&#xff0c; 此测试的目的是对类Unix 系统提供一个基本的性能指示&#xff0c;很多测试用于系统性能的不同方面&#xff0c;这些测试的结果是一个指数值&#xff08;index value&am…