0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙开发案例:【图像加载缓存库ImageKnife】

jf_46214456 来源:jf_46214456 作者:jf_46214456 2024-03-23 16:48 次阅读

ImageKnife

专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单。

简介

OpenHarmony的自研版本:

  • 支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。
  • 支持磁盘缓存,对于下载图片会保存一份至磁盘当中。
  • 支持进行图片变换: 支持图像像素源图片变换效果。
  • 支持用户配置参数使用:( 例如:配置是否开启一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。
  • 推荐使用ImageKnifeComponent组件配合ImageKnifeOption参数来实现功能。
  • 支持用户自定义配置实现能力参考ImageKnifeComponent组件中对于入参ImageKnifeOption的处理。

下载安装

ohpm install @ohos/imageknife

使用说明

1.依赖配置

在entrysrcmainetsentryabilityEntryAbility.ts中做如下配置初始化全局ImageKnife实例:

import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import { ImageKnife } from '@ohos/imageknife'

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    windowStage.loadContent('pages/Index', (err, data) = > {
    });
    // 初始化全局ImageKnife 
    ImageKnife.with(this.context);
  	// 后续访问ImageKnife请通过:ImageKnifeGlobal.getInstance().getImageKnife()方式
  }
}

2.加载普通图片

接下来我们来写个简单实例看看:

import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'
  @State option: ImageKnifeOption = {
    loadSrc: $r('app.media.icon')
  }

  build() {
      Row() {
        Column() {
          Text(this.message)
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
          ImageKnifeComponent({ imageKnifeOption: this.option })
            .width(300)
            .height(300)
        }.width('100%')
      }.height('100%')
  }
}

非常简单,仅需定义一个ImageKnifeOption数据对象,然后在你需要的UI位置,加入ImageKnifeComponent自定义组件就可以加载出一张图像了。

3.加载SVG图片

加载svg其实和普通流程没有区别,只要将 loadSrc: $r('app.media.jpgSample'),``改成一张 loadSrc: $r('app.media.svgSample'), svg类型图片即可。

4.加载GIF图片

加载GIF其实和普通流程也没有区别只要将 loadSrc: $r('app.media.jpgSample'),``改成一张 loadSrc: $r('app.media.gifSample'), GIF图片即可。

5.自定义Key

因为通常改变标识符比较困难或者根本不可能,所以ImageKnife也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。 签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。

将签名传入加载请求

imageKnifeOption = {
                loadSrc: 'https://aahyhy.oss-cn-beijing.aliyuncs.com/blue.jpg',
                signature: new ObjectKey(new Date().getTime().toString())
              }

详细样例请参考SignatureTestPage文件

代码示例

进阶使用

如果简单的加载一张图像无法满足需求,我们可以看看ImageKnifeOption这个类提供了哪些扩展能力。

ImageKnifeOption参数列表

参数名称入参内容功能简介
loadSrcstringPixelMap
mainScaleTypeScaleType设置主图展示样式(可选)
strategyDiskStrategy设置磁盘缓存策略(可选)
dontAnimateFlagbooleangif加载展示一帧(可选)
placeholderSrcPixelMapResource
placeholderScaleTypeScaleType设置占位图展示样式(可选)
errorholderSrcPixelMapResource
errorholderSrcScaleTypeScaleType设置失败占位图展示样式(可选)
retryholderSrcPixelMapResource
retryholderScaleTypeScaleType设置重试占位图展示样式(可选)
thumbSizeMultipliernumber 范围(0,1]设置缩略图占比(可选)
thumbSizeDelaynumber设置缩略图展示时间(可选)
thumbSizeMultiplierScaleTypeScaleType设置缩略图展示样式(可选)
displayProgressboolean设置是否展示下载进度条(可选)
canRetryClickboolean设置重试图层是否点击重试(可选)
onlyRetrieveFromCacheboolean仅使用缓存加载数据(可选)
isCacheableboolean是否开启一级内存缓存(可选)
gif{ // 返回一周期动画gif消耗的时间 loopFinish?: (loopTime?) => void // gif播放速率相关 speedFactory?: number // 直接展示gif第几帧数据 seekTo?: number }GIF播放控制能力(可选)
transformationBaseTransform单个变换(可选)
transformationsArray多个变换,目前仅支持单个变换(可选)
allCacheInfoCallbackIAllCacheInfoCallback输出缓存相关内容和信息(可选)
signatureObjectKey自定key(可选)
drawLifeCycleIDrawLifeCycle用户自定义实现绘制方案(可选)
imageSmoothingEnabledboolean抗锯齿是否开启属性配置,设置为false时,imageSmoothingQuality失效
imageSmoothingQualityAntiAliasing抗锯齿属性配置

其他参数只需要在ImageKnifeOption对象上按需添加即可。

这里我们着重讲一下 自定义实现绘制方案 。为了增强绘制扩展能力,目前ImageKnifeComponent使用了Canvas的渲染能力作为基础。在此之上为了抽象组件绘制表达。我将图像的状态使用了 IDrawLifeCycle绘制生命周期进行表达

大致流程 展示占位图->展示网络加载进度->展示缩略图->展示主图->展示重试图层->展示失败占位图

ImageKnifeComponent内部,责任链实现。 用户参数设置->全局参数设置->自定义组件内部设置

采用责任链的好处是,用户可以通过自定义绘制,重新绘制图层。如果不想绘制也可以通过预制回调获取绘制流程信息。

场景1:默认的展示不满足需求,需要加个圆角效果。

代码如下:

import { ImageKnifeComponent } from '@ohos/imageknife'
import { ImageKnifeOption } from '@ohos/imageknife'
import { ImageKnifeDrawFactory } from '@ohos/imageknife'

@Entry
@Component
struct Index {
  @State imageKnifeOption1: ImageKnifeOption = { 
      // 加载一张本地的jpg资源(必选)
      loadSrc: $r('app.media.jpgSample'),
      // 占位图使用本地资源icon_loading(可选)
      placeholderSrc: $r('app.media.icon_loading'),
      // 失败占位图使用本地资源icon_failed(可选)
      errorholderSrc: $r('app.media.icon_failed'),
      // 绘制圆角30,边框5,边框"#ff00ff".用户自定义绘制(可选)
      drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)
    };
        
    build(){
        Scroll() {
          Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
            ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
            .width(300) 
            .height(300)
          }
        }
        .width('100%')
        .height('100%')
    }
}

ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30) 我们深入查看源码可以发现,实际上是对IDrawLifeCycle接口的部分实现,这里我介绍一下IDrawLifeCycle。

IDrawLifeCycle的返回值代表事件是否被消费,如果被消费接下来组件内部就不会处理,如果没被消费就会传递到下一个使用者。目前消费流程(用户自定义-> 全局配置定义->组件内部默认定义) *

所以我们在当数据是一张PixelMap的时候(目前jpg png bmp webp svg返回的都是PixelMap,gif返回GIFFrame数组),我们返回了true。消费了事件,代表这个绘制流程用户自定义完成。

由于IDrawLifeCycle实现较为冗长,我们封装了ImageKnifeDrawFactory工厂,提供了网络下载百分比效果、圆角、椭圆添加边框等能力。下面我们就再看看使用工厂封装之后的场景代码。

场景2: 网络下载百分比效果展示

当进行加载网络图片时,可能需要展示网络下载百分比动画。但是默认的动画又不能满足需求,这个时候我们就需要自定义网络下载百分比效果。代码如下:

import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import { ImageKnifeGlobal,ImageKnife,ImageKnifeDrawFactory,LogUtil } from '@ohos/imageknife'
import abilityAccessCtrl,{Permissions} from '@ohos.abilityAccessCtrl';
export default class EntryAbility extends UIAbility {
    onWindowStageCreate(windowStage: window.WindowStage) {
        //.. 删除不必要代码
        windowStage.loadContent('pages/index', (err, data) = > {
        });
       	// 初始化ImageKnifeGlobal和ImageKnife
        ImageKnife.with(this.context);
        // 全局配置网络加载进度条 使用ImageKnifeGlobal.getInstance().getImageKnife()访问ImageKnife
ImageKnifeGlobal.getInstance().getImageKnife().setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
    }
}

这里大家可能会问,为什么会将这个IDrawLifeCycle放在AbilityStage里面实现?

这是因为网络下载百分比进度很多时候都是全局通用,如果有需要全局配置的自定义展示方案。推荐在AbilityStage里面,往ImageKnife的setDefaultLifeCycle函数中注入,即可将ImageKnifeComponent中的默认绘制方案替换。

在这里我们实现的效果如下图所示。

高级用法

以上简单使用和进阶使用都是经过一层自定义组件封装之后形成的,RequestOption封装成了ImageKnifeOption,绘制部分封装成了自定义组件ImageKnifeComponent。

如果用户其实并不关心绘制部分,或者说想用自己的通用方案对自定义组件ImageKnifeComponent重构都是可以的。

下面我们会着重指导用户如何复用图片加载逻辑,重构自定义组件ImageKnifeComponent。

首先我们先看看RequestOption构建的内容,如下所示:

数据加载

RequestOption构建:

请查阅下文接口内容:[RequestOption接口方法]

了解了RequestOption的参数内容后,我们可以参考ImageKnifeComponent组件代码进行分析。

imageKnifeExecute()函数入口,首先我们需要构建一个RequestOption对象,let request = new RequestOption(), 接下来就是按需配置request对象的内容,最后使用 ImageKnifeGlobal.getInstance().getImageKnife()?.call(request)发送request执行任务即可。

是不是很简单,而其实最重要的内容是就是: 按需配置request对象的内容 为了更好理解,我举例说明一下:

场景一: 简单加载一张图片

let request = new RequestOption();
// (必传)
request.load("图片url")
  // (可选 整个request监听回调)
	.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) = > {
	// data 是ImageKnifeData对象
	if(data.isPixelMap()){
	// 这样就获取到了目标PixelMap
	let pixelmap = data.drawPixleMap.imagePixelMap;
	}
    return false;
  })
 
  let compSize:Size = {
    width: this.currentWidth,
    height:this.currentHeight
  }
  // (必传)这里setImageViewSize函数必传组件大小,因为涉及到图片变换效果都需要适配图像源和组件大小
 request.setImageViewSize(compSize)
 // 最后使用ImageKnife的call函数调用request即可
 let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
 if(imageKnife != undefined){
 	imageKnife.call(request)
 }

其他场景,可以按需加载

比如我需要配置 占位图 只需要 在request对象创建好之后,调用 placeholder 函数即可

request.placeholder(this.imageKnifeOption.placeholderSrc, (data) = > {
  console.log('request.placeholder callback')
  this.displayPlaceholder(data)
})

再比如 我对缓存配置有要求,我要禁用内存缓存,调用 skipMemoryCache 函数即可

request.skipMemoryCache(true)

这里只是简单介绍部分使用,更多的内容请参考 按需加载 原则,并且可以参考ImageKnifeComponent源码或者根据文档自行探索实现。

接口说明

RequestOption用户配置参数

方法名入参接口描述
load(src: stringPixelMapResource)
setImageViewSize(imageSize: { width: number, height: number })imageSize:{width: number, height: number }传入显示图片组件的大小,变换的时候需要作为参考
diskCacheStrategy(strategy: DiskStrategy)strategy:DiskStrategy配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC
placeholder(src: PixelMapResource, func?: AsyncSuccess)src: PixelMap
errorholder(src: PixelMapResource, func?: AsyncSuccess)src: PixelMap
retryholder(src: PixelMapResource, func?: AsyncSuccess)src: PixelMap
addListener(func: AsyncCallback)func: AsyncCallback配置整个监听回调,数据正常加载返回,加载失败返回错误信息
thumbnail(sizeMultiplier:number, func?: AsyncSuccess)sizeMultiplier:number, func?: AsyncSuccess设置缩略图比例,缩略图返回后,加载并展示缩略图
addProgressListener(func?: AsyncSuccess)func?: AsyncSuccess设置网络下载百分比监听,返回数据加载百分比数值
addAllCacheInfoCallback(func: IAllCacheInfoCallback)func: IAllCacheInfoCallback设置获取所有缓存信息监听
skipMemoryCache(skip: boolean)skip: boolean配置是否跳过内存缓存
retrieveDataFromCache(flag: boolean)flag: boolean配置仅从缓存中加载数据
signatureObjectKey自定义key

同时支持[图片变换相关]接口。

ImageKnife 启动器/门面类

方法名入参接口描述
call(request: RequestOption)request: RequestOption根据用户配置参数具体执行加载流程
preload(request: RequestOption)request: RequestOption根据用户配置参数具体执行预加载流程
pauseRequests()全局暂停请求
resumeRequests()全局恢复暂停

缓存策略相关

使用方法类型策略描述
request.diskCacheStrategy(new ALL())ALL表示既缓存原始图片,也缓存转换过后的图片
request.diskCacheStrategy(new AUTOMATIC())AUTOMATIC表示尝试对本地和远程图片使用适合的策略
request.diskCacheStrategy(new DATA())DATA表示只缓存原始图片
request.diskCacheStrategy(new NONE())NONE表示不缓存任何内容
request.diskCacheStrategy(new RESOURCE())RESOURCE表示只缓存转换过后的图片

AntiAliasing类型展示效果

使用方法类型策略描述
AntiAliasing.FIT_HIGHString图像抗锯齿设置为高画质
AntiAliasing.FIT_MEDIUMString图像抗锯齿设置为中画质
AntiAliasing.FIT_LOWString图像抗锯齿设置为低画质

ScaleType类型展示效果

使用方法类型策略描述
ScaleType.FIT_STARTint图像位于用户设置组件左上角显示,图像会缩放至全部展示
ScaleType.FIT_ENDint图像位于用户设置组件右下角显示,图像会缩放至全部展示
ScaleType.FIT_CENTERint图像位于用户设置组件居中,图像会缩放至全部展示
ScaleType.CENTERint图像居中展示,不缩放
ScaleType.CENTER_CROPint图像的宽高长度,短的部分缩放至组件大小,超出的全部裁剪
ScaleType.FIT_XYint图像拉伸至组件大小
ScaleType.CENTER_INSIDEint如果图像大于组件则执行FIT_CENTER,小于组件则CENTER
ScaleType.NONEint如果不想适配,直接展示原图大小

图片变换相关

使用方法类型相关描述
request.centerCrop()CenterCrop可以根据图片文件,目标显示大小,进行对应centerCrop
request.centerInside()CenterInside可以根据图片文件,目标显示大小,进行对应centerInside
request.fitCenter()FitCenter可以根据图片文件,目标显示大小,进行对应fitCenter
request.blur()BlurTransformation模糊处理(图片分辨率较大建议传递第二个参数将图片进行缩小)
request.ightnessFilter()BrightnessFilterTransformation亮度滤波器
request.contrastFilter()ContrastFilterTransformation对比度滤波器
request.cropCircle()CropCircleTransformation圆形剪裁显示
request.cropCircleWithBorder()CropCircleWithBorderTransformation圆环展示
request.cropSquare()CropSquareTransformation正方形剪裁
request.crop()CropTransformation自定义矩形剪裁
request.grayscale()GrayscaleTransformation灰度级转换
request.invertFilter()InvertFilterTransformation反转滤波器
request.pixelationFilter()PixelationFilterTransformation像素化滤波器
request.rotateImage()RotateImageTransformation图片旋转
request.roundedCorners()RoundedCornersTransformation圆角剪裁
request.sepiaFilter()SepiaFilterTransformation乌墨色滤波器
request.sketchFilter()SketchFilterTransformation素描滤波器
request.mask()MaskTransformation遮罩
request.swirlFilter()SwirlFilterTransformation扭曲滤波器
request.kuwaharaFilter()KuwaharaFilterTransform桑原滤波器
request.toonFilter()ToonFilterTransform动画滤波器
request.vignetteFilter()VignetteFilterTransform装饰滤波器

setLruCacheSize

setLruCacheSize(size: number,memory:number): void

设置图片文件缓存的大小上限,size单位为张数,memory单位为字节,提升再次加载同源图片的加载速度,特别是对网络图源会有较明显提升。 如果不设置则默认为100张,100MB。缓存采用内置的LRU策略。 size为0则代表不限制缓存张数,memory为0则代表不限制缓存大小。 建议根据应用实际需求,设置合理缓存上限,数字过大可能导致内存占用过高,可能导致OOM异常。

参数:

参数名类型必填说明
sizenumber图片文件的缓存张数,单位为张。只支持正整数,0
memorynumber图片文件的缓存大小,单位为字节。只支持正数,0

示例:

//EntryAbility.ets
import { InitImageKnife } from '...imageknife'
export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) { 
    InitImageKnife.init(this.context);
    let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
    if (imageKnife != undefined) {
      //设置全局内存缓存大小张数
      imageKnife.setLruCacheSize(100, 100 * 1204 * 1024)
    }
  }
}

约束与限制

在下述版本验证通过: DevEco Studio 4.1(4.1.3.520)--SDK:API11( 4.1.0.63) DevEco Studio 4.1(4.1.3.418)--SDK:API11( 4.1.0.56) DevEco Studio 4.1(4.1.3.322)--SDK:API11( 4.1.0.36) DevEco Studio 4.0(4.0.3.700)--SDK:API10( 4.0.10.15)

HSP场景适配:

在使用ImageKnifeComponent进行加载图片时, 提供的ImageKnifeOption配置类新增了可选参数context, 在HSP场景下需要传入正确的context, 才能保证三方库后续正确获取Resource资源。

在使用RquestOption进行加载图片时, 提供的RquestOption配置类新增了接口setModuleContext(moduleCtx:common.UIAbilityContext), 在HSP场景下需要传入正确的context, 才能保证三方库后续正确获取Resource资源。

非HSP场景不影响原功能, ImageKnifeOption配置类新增的可选参数context可以不传, RquestOption配置类新增的接口可以不调用。

更多鸿蒙开发知识已经更新在[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]前往参考。

HarmonyOS与OpenHarmony技术路线曲线图1.png

遗留问题

1.目前只支持一种图片变换效果。

2.目前svg和gif动图不支持变换效果。

补充说明

SVG标签说明

使用版本为(SVG)1.1,当前支持的标签列表有:

  • a
  • circla
  • clipPath
  • defs
  • ellipse
  • feBlend
  • feColorMatrix
  • feComposite
  • feDiffuseLighting
  • feDisplacementMap
  • feDistantLight
  • feFlood
  • feGaussianBlur
  • feImage
  • feMorphology
  • feOffset
  • fePointLight
  • feSpecularLighting
  • feSpotLight
  • feTurbulence
  • filter
  • g
  • image
  • line
  • linearGradient
  • mask
  • path
  • pattern
  • polygon
  • polyline
  • radialGradient
  • rect
  • stop
  • svg
  • text
  • textPath
  • tspan
  • use

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 鸿蒙
    +关注

    关注

    57

    文章

    2449

    浏览量

    43384
  • OpenHarmony
    +关注

    关注

    25

    文章

    3779

    浏览量

    17215
收藏 人收藏

    相关推荐

    Get这个秘籍,鸿蒙原生应用页面滑动丝滑无比

    Prefetcher接口监听数据项的变化,动态控制资源的下载与取消,并结合ImageKnife三方实现具体的预取和缓存管理。这种动态预加载策略突破了以往解决方案的局限性,提供了一种更
    发表于 03-06 14:41

    FPGA图像处理基础----实现缓存卷积窗口

    素行进行缓存与变换。由于在图像处理过程中,经常会使用到卷积,因此需要对图像进行开窗,然后将开窗得到的局部图像与卷积核进行卷积,从而完成处理。   
    的头像 发表于 02-07 10:43 361次阅读
    FPGA<b class='flag-5'>图像</b>处理基础----实现<b class='flag-5'>缓存</b>卷积窗口

    #新年新气象,大家新年快乐!#AIGC入门及鸿蒙入门

    。 2. 实践操作: 使用Python进行实践,通过transformers加载预训练的文本生成模型。 学习图像生成算法,如生成对抗网络(GAN)等。 3. 工具推荐: ChatGPT:由OpenAI
    发表于 01-13 10:46

    AIGC入门及鸿蒙入门

    。 2. 实践操作: 使用Python进行实践,通过transformers加载预训练的文本生成模型。 学习图像生成算法,如生成对抗网络(GAN)等。 3. 工具推荐: ChatGPT:由OpenAI
    发表于 01-13 10:32

    鸿蒙原生页面高性能解决方案上线OpenHarmony社区 助力打造高性能原生应用

    ,大幅缩短了冷启动时间。此外,它提供通用本地缓存,帮助开发者更快实现缓存逻辑,提高开发效率与应用体验。某头部网盘APP使用该方案后,首页冷
    发表于 01-02 18:00

    鸿蒙Flutter实战:14-现有Flutter 项目支持鸿蒙 II

    ,职责分离,平台抽象,不同平台组合打包,有效解决平台不一致问题 参考资料 鸿蒙Flutter实战:01-搭建开发环境 鸿蒙Flutter实战:09-现有Flutter项目支持鸿蒙 Fl
    发表于 12-26 14:59

    鸿蒙原生开源ViewPool在OpenHarmony社区正式上线

    近日,由伙伴参与共建的鸿蒙原生开源“ViewPool”在OpenHarmony社区正式上线。这个开发是基于OpenHarmony技术孵化的成果,充分发挥了平台的技术特性,同时融入了
    的头像 发表于 12-20 14:44 429次阅读

    HTTP缓存头的使用 本地缓存与远程缓存的区别

    HTTP缓存头是一组HTTP响应头,它们控制浏览器和中间代理服务器如何缓存网页内容。合理使用HTTP缓存头可以显著提高网站的加载速度和性能,减少服务器的负载。 1. HTTP
    的头像 发表于 12-18 09:41 275次阅读

    鸿蒙原生应用元服务开发WEB-缓存与存储管理

    缓存模式,Web组件为开发者提供四种缓存模式,分别为: Default : 优先使用未过期的缓存,如果缓存不存在,则从网络获取。 None
    发表于 05-17 11:23

    纯血鸿蒙开发教程-运行时动态加载页面提升性能

    ,主页内存占用增加,加载时间变长。此时改用动态加载不再提前加载子页面,可以有效地避免这些任务阻塞主线程,从而降低整体资源消耗,提高主页的加载速度。 最后 如果大家觉得这篇内容对学习
    发表于 05-10 20:52

    HarmonyOS开发案例:【Web组件实现抽奖】

    基于ArkTS的声明式开发范式的样例,主要介绍了Web组件如何加载本地和云端H5小程序。
    的头像 发表于 05-09 18:31 1501次阅读
    HarmonyOS<b class='flag-5'>开发案</b>例:【Web组件实现抽奖】

    HarmonyOS开发案例:【新闻数据加载

    基于ArkTS的声明式开发范式实现的样例,主要介绍了数据请求和touch事件的使用。
    的头像 发表于 04-22 17:22 680次阅读
    HarmonyOS<b class='flag-5'>开发案</b>例:【新闻数据<b class='flag-5'>加载</b>】

    HarmonyOS携手洛游戏推动《战双帕弥什》鸿蒙原生应用开发

    4 月 22 日,华为宣布洛游戏的《战双帕弥什》正式启动鸿蒙原生应用开发项目,与 HarmonyOS NEXT 鸿蒙星河版的方舟引擎展开深度合作,旨在提升游戏的运行流畅度,为玩家提供
    的头像 发表于 04-22 15:21 771次阅读

    3568F-视频开发案

    3568F-视频开发案
    的头像 发表于 04-12 13:51 977次阅读
    3568F-视频<b class='flag-5'>开发案</b>例

    鸿蒙NEXT南向开发案例:【智能台灯】

    鸿蒙南向开发之智能台灯案例
    的头像 发表于 04-03 18:00 1175次阅读
    <b class='flag-5'>鸿蒙</b>NEXT南向<b class='flag-5'>开发案</b>例:【智能台灯】