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

news/2024/4/28 7:12:52/文章来源:https://blog.csdn.net/2301_76813281/article/details/137125677

介绍

服务卡片指导文档位于“开发/应用模型/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.luyixian.cn/news_show_1026869.aspx

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

相关文章

Java实现猜数字游戏:编程入门之旅

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

打造核心竞争力:高效Web系统数据中台的设计与实践_光点科技

在数字化的浪潮中&#xff0c;数据已经成为企业赖以生存和发展的核心资源。一个高效的Web系统数据中台&#xff0c;能够赋予企业在激烈的市场竞争中立于不败之地的能力。本文将深入探讨如何设计和实施一个能够提升企业数据管理水平和支持业务决策的高效数据中台架构。 数据中台…

二进制王国(蓝桥杯备赛)【sort/cmp的灵活应用】

二进制王国 题目链接 https://www.lanqiao.cn/problems/17035/learning/?contest_id177 题目描述 思路 这里就要灵活理解字典序排列&#xff0c;虽然string内置可以直接比较字符串字典序&#xff0c;但是在拼接时比较特殊&#xff0c;比如 11的字典序小于110&#xff0c;但…

【AI】大模型API调研及推荐

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 【AI】大模型API调研及推荐引入调研KimiAPI对接 国内GPT4的转发API对接 总结 【AI…

探秘PHP之美:Laravel项目架构与运行原理

在当今Web开发领域&#xff0c;PHP语言以其灵活性和便捷性成为开发者们的首选之一。而在众多PHP框架中&#xff0c;Laravel凭借其优雅的设计和强大的功能成为了众多开发者心目中的首选。本文将深入探讨Laravel项目的架构与运行原理&#xff0c;揭示其内在的美感与魅力。 --- …

Python列表、元组、字典及集合

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、列表定义方式&#xff1a; 二、元组1、定义方式&#xff1a;2、元组中的物理存储地址不可修改,如果修改则会报错&#xff0c;但是元组中的列表、字典项等却可以…

Tesla技术方案解析

Tesla技术方案解析 附赠自动驾驶学习资料和量产经验&#xff1a;链接 参考&部分摘选&#xff1a; EatElephant&#xff1a;解读: Tesla Autopilot技术架构 chenq100&#xff1a;TechTips - 031: “Tesla AI Day 2021”学习笔记 All you need to know about Tesla AI Da…

Llama模型下载

最近llama模型下载的方式又又变了&#xff0c;所以今天简单更新一篇文章&#xff0c;关于下载的&#xff0c;首先上官网&#xff0c;不管在哪里下载你都要去官网登记一下信息&#xff1a;https://llama.meta.com/llama2 然后会出现下面的信息登记网页&#xff1a; 我这里因为待…

鸿蒙OS开发实例:【Web网页】

背景 HarmonyOS平台通过Web控件可支持网页加载展示&#xff0c;Web在中是作为专项参考的。 本篇文章将从Android和iOS平台研发角度出发来实践学习API功能 说明 整个示例是以HarmonyOS开发文档网址作为加载目标页面布局增加了三个按钮“后退”&#xff0c;“前进”&#xff…

搭建vite项目

文章目录 Vite 是一个基于 Webpack 的开发服务器&#xff0c;用于开发 Vue 3 和 Vite 应用程序 一、创建一个vite项目二、集成Vue Router1.安装 vue-routernext插件2.在 src 目录下创建一个名为 router 的文件夹&#xff0c;并在其中创建一个名为 index.js 的文件。在这个文件中…

【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串

送给大家一句话&#xff1a; 充满着欢乐与斗争精神的人们&#xff0c;永远带着欢乐&#xff0c;欢迎雷霆与阳光。 —— 赫胥黎 滑动窗口精通 前言Leetcode 30. 串联所有单词的子串题目描述算法思路 Leetcode 76. 最小覆盖子串题目描述算法思路 Thanks♪(&#xff65;ω&#xf…

45.跳跃游戏||

// 定义一个名为Solution的类 class Solution {// 定义一个public方法jump&#xff0c;输入参数为一个整数数组nums&#xff0c;返回值类型为整数public int jump(int[] nums) {// 初始化跳跃次数结果变量为0int result 0;// 初始化当前覆盖的最远距离下标为0int end 0;// 初…

【随笔】Git -- 基本概念和使用方式(五)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

安卓利用CameraX 拍照获这张照片的exif信息

一、首先导入相关权限 <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-featureandroid:name"android.hardware.camera"android:required"true" /><uses-permission android:name"andro…

2014年认证杯SPSSPRO杯数学建模B题(第一阶段)位图的处理算法全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 B题 位图的处理算法 原题再现&#xff1a; 图形&#xff08;或图像&#xff09;在计算机里主要有两种存储和表示方法。矢量图是使用点、直线或多边形等基于数学方程的几何对象来描述图形&#xff0c;位图则使用像素来描述图像。一般来说&#…

Leetcode LRU---哈希➕双链表

题目链接 讲解视频 Tips&#xff1a; 代码&#xff1a; import java.util.*; // 修改导入语句&#xff0c;正确引入 java.util 包class Node{//双链表int key,value;Node pre,next;public Node(int k,int v){this.key k;this.value v;this.pre null;this.next null;}…

OpenHarmony实战开发-从0到1实现购物应用页面

概述 OpenHarmony ArkUI框架提供了丰富的动画组件和接口&#xff0c;开发者可以根据实际场景和开发需求&#xff0c;选用丰富的动画组件和接口来实现不同的动画效果。 本Codelab中&#xff0c;我们会构建一个简易的购物应用。应用包含两级页面&#xff0c;分别是主页&#xf…

【Nebula笔记】基础操作

目录 一、预备~ 二、基础操作 (一) 图空间 1. 创建图空间 2. 清空图空间 3. 其他 4. FAQ 执行DROP SPACE语句删除图空间后&#xff0c;为什么磁盘的大小没变化&#xff1f; (二) 点类型 1. 创建Tag 2. 删除Tag 3. 更新Tag 4. 其他 (三) 边类型 1. 创建Edge type…

ubuntu系统下如何使用vscode编译和调试#小白入门#

编程环境&#xff1a;ubuntu系统为18.04.1&#xff0c;vscode版本为1.66.2 一、VSCode切换中文显示&#xff1a; 1、vscode安装完成后启动,在左侧externsions中搜索“简体中文”插件&#xff0c;并完成安装&#xff1a; 2、选择右下角齿轮形状的"Manage"&#xff…

自然指数函数e^x与欧拉数e (下)

自然指数函数e^x与欧拉数e Part I: 如何找到欧拉数e 上一篇文章停在了“应该存在一个b&#xff0c;使得指数函数b^x在x0处的导数为1。且该指数函数在任意一处的导数都等于当前位置的函数值”。根据前面所知道的&#xff0c;可以用数学公式列出以下一些已知条件&#xff1a; &am…