基于ArkUI框架开发-ImageKnife渲染层重构

ImageKnife是一款图像加载缓存库,主要功能特性如下:

●支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。

●支持磁盘缓存,对于下载图片会保存一份至磁盘当中。

●支持进行图片变换:支持图像像素源图片变换效果。

●支持用户配置参数使用:(例如:配置是否开启一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。

背景说明

早期ImageKnife三方库在实现渲染部分的时候,使用的是image组件来展示图片的。由于image组件其实是一个完整的集加载解析和图片展示的组件,渲染的模式只能通过配置固定参数进行,面对复杂的需求场景,可能会出现扩展性不够的情况。

现在随着时间的推移渲染组件又多了一位重量级选手Canvas组件。可以通过2个组件渲染层的能力对比进行判断渲染层最终交由哪个组件展示。

组件选型,能力对比

首先我们来看看Image组件和Canvas组件对于渲染这一块的支持情况。

从上表我们可以看出:

Image组件虽然支持了PixelMap的绘制,但是基本没有绘制控制能力,而且扩展性能力也比较弱,并且渲染过程不可见,也无法对绘制内容进行更多操作。

而Canvas组件属于更加底层的渲染组件,可以完美地控制绘制内容,并且渲染过程可见,符合了开发者对于扩展性要求较高的定制场景。

重构前后能力对比

重构完成的内容

1. 使用canvas组件替代Image组件进行渲染展示图片。
2. 所有图像数据在渲染层都转换为PixelMap,方便统一管理和扩展。
3. 所有回调节点,统一抽象成接口,方便后续进行扩展,提高代码可维护性。
4. 所有的回调节点绘制的实现,都采用了责任链模式,提高了自定义绘制扩展能力。
5. 将部分通用方法封装成工厂方法,减少开发者代码量。
6. 通用方法从配置参数剥离,可采用链式调用方式使用这些方法。
7. 为了支持列表ImageKnifeOption参数使用@LinkObject修饰,同时ImageKnifeOption类型被@Observed修饰继承,不可被继承。

重构中比较重要的点

点1:回调接口抽象为IDrawLifeCycle接口

渲染绘制是主线程才能操作。因此我们可以对渲染顺序进行了梳理,大致流程:展示占位图->展示网络加载进度->展示缩略图->展示主图->展示重试图层->展示失败占位图

这里每个蓝色的小方格都代表着一个数据返回的回调接口,我们需要在这个回调接口,处理接下来内容渲染的展示操作。因为每个回调的流程是固定的,有点像生命周期的流程。所以我这边抽象成接口IDrawLifeCycle绘制生命周期进行表达。这其实也是为了后面扩展做了准备。

点2:绘制实现采用责任链模式

我们支持了用户配置自定义绘制和全局配置自定义绘制的能力。采用了责任链模式实现,用户参数设置->全局参数设置->自定义组件内部设置。这样设计的好处就是保留了用户扩展的能力,用户可以参与自定义绘制。

点3:提供了ImageKnifeDrawFactory工厂类

在开发者需要进行自定义绘制时,必须实现IDrawLifeCycle的6个接口。为了简化开发者操作,这里提供了ImageKnifeDrawFactory工厂类。

ImageKnifeDrawFactory里面封装了圆角、椭圆、百分比下载等实现,简化用户操作。当然更多的需求,可以参考该工厂类自行扩展实现。

这里我们提供简单的场景示例:

场景1:一句代码,加个圆角效果

代码如下:

 1 import {ImageKnifeComponent} from '@ohos/imageknife'
 2 import {ImageKnifeOption} from '@ohos/imageknife'
 3 import {ImageKnifeDrawFactory} from '@ohos/imageknife'
 4 @Entry
 5 @Component
 6 struct Index {
 7   @State imageKnifeOption1: ImageKnifeOption =
 8     { // 加载一张本地的png资源(必选)
 9       loadSrc: $r('app.media.pngSample'),
10       // 主图的展示模式是 缩放至适合组件大小,并且在组件底部绘制
11       mainScaleType: ScaleType.FIT_END,
12       // 占位图使用本地资源icon_loading(可选)
13       placeholderSrc: $r('app.media.icon_loading'),
14       // 失败占位图使用本地资源icon_failed(可选)
15       errorholderSrc: $r('app.media.icon_failed'),
16       // 绘制圆角30,边框5,边框"#ff00ff".用户自定义绘制(可选)
17       drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)
18     };
19   build() {
20     Scroll() {
21       Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
22         ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
23           .width(300) // 自定义组件已支持设置通用属性和事件,这里宽高设置放在链式调用中完成
24           .height(300)
25       }
26     }
27     .width('100%')
28     .height('100%')
29   }
30 }

场景2:全局配置网络下载百分比效果展示

仅需一句代码所有网络图片加载都能新增网络下载百分比效果展示。代码如下:

 1 import AbilityStage from '@ohos.application.Ability'
 2 import { ImageKnife,ImageKnifeDrawFactory} from '@ohos/imageknife'
 3 
 4 export default class EntryAbility extends Ability {
 5     onCreate(want,launchParam) {
 6         globalThis.ImageKnife = ImageKnife.with(this.context);
 7         // 全局配置网络加载进度条       
 8         globalThis.ImageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5))
 9     }
10 }

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

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

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

点4:通用属性方法和属性已经支持链式调用

比如下面的代码的宽高已经不用设置在ImageKnifeOption对象中了,直接在自定义组件下方链式调用设置即可。

 1 import {ImageKnifeComponent,ImageKnifeOption,ImageKnifeDrawFactory} from '@ohos/imageknife'
 2 @Entry
 3 @Component
 4 struct Index {
 5   @State imageKnifeOption1: ImageKnifeOption =
 6     { // 加载一张本地的png资源(必选)
 7       loadSrc: $r('app.media.pngSample'),
 8     };
 9   build() {
10     Scroll() {
11       Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
12         ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
13           .width(300) // 自定义组件已支持设置通用属性和事件,这里宽高设置放在链式调用中完成
14           .height(300)
15       }
16     }
17     .width('100%')
18     .height('100%')
19   }
20 }

点5:如何在列表使用

支持列表使用图片加载,只需要维护一个@State options:Array = []

对象即可

 1 import {ImageKnifeOption,ImageKnifeComponent} from '@ohos/imageknife'
 2 @Entry
 3 @Component
 4 struct BasicTestFeatureAbilityPage {
 5   urls=[
 6    "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
 7    "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
 8    "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
 9    "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
10    "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
11  ]
12   @State options:Array<ImageKnifeOption> = []
13   aboutToAppear(){
14     this.options =  this.urls.map((url)=>{
15       return {
16         loadSrc:url
17       }
18     })
19     console.log('this.options length ='+this.options.length)
20   }
21   build() {
22     Stack({ alignContent: Alignment.TopStart }) {
23       Column() {
24         List({ space: 20, initialIndex: 0 }) {
25           ForEach(this.options, (item) => {
26             ListItem() {
27               ImageKnifeComponent({imageKnifeOption:item}).width(300).height(300)
28             }
29           }, item => item.loadSrc)
30         }
31         .listDirection(Axis.Vertical) // 排列方向
32         .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
33         .edgeEffect(EdgeEffect.None) // 滑动到边缘无效果
34         .chainAnimation(false) // 联动特效关闭
35       }.width('100%')
36     }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
37   }
38 }

渲染层重构的总结

综上可知,此次重构渲染层,一共新增了6个基础能力,适配了IDE最新版特性自定义组件可链式调用通用属性和方法,并且采用适合的设计模式保留了自定义组件绘制部分的拓展能力。展示了部分常用场景下使用代码的方式,帮助开发者更快上手开发。

最后在OpenHarmony不断推陈出新之际,三方库ImageKnife也应该激流勇进,不断地提升组件的实用性和适用性,为开发者创造一个良好的开发体验。

我们将会持续更新ImageKnife三方库,后续会切换成GPU来渲染图片变换能力,不断进行性能优化,提升ImageKnife三方库。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

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

相关文章

如何用Airtest脚本连接无线Android设备?

之前我们已经详细介绍过如何用AirtestIDE无线连接Android设备&#xff0c;它的关键点在于&#xff0c;需要先 adb connect 一次&#xff0c;才能点击 connect 按钮无线连接上该设备&#xff1a; 但是有很多同学&#xff0c;在使用纯Airtest脚本的形式连接无线设备时&#xff0c…

IObit Uninstaller Pro:一键强力卸载,让您的电脑焕然一新

在数字化时代&#xff0c;电脑已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着我们使用电脑的时间越来越长&#xff0c;安装的软件也越来越多&#xff0c;电脑的性能往往会逐渐下降&#xff0c;甚至出现卡顿、崩溃等问题。这些问题往往源于一些难以卸载的顽固…

[蓝桥杯 2020 省 AB1] 网络分析

一开始写的暴力合并 卡n^2过的不是正解 看正解是类似 虚拟点树形DP的思路 很巧妙 记录一下 #include<bits/stdc.h> using namespace std; using ll long long; using pii pair<int,int>; #define int long long const int N 3e510; const int inf 0x3f3f3f3f; …

STL ④ —— 哈希

1. 散列表 根据 key 计算 key 在表中的位置的数据结构&#xff1b;是 key 和其所在存储地址的映射关系&#xff0c;即 hash(key) % size index struct node{void *key;void *value;struct node *next; };2. hash函数 2.1 hash函数的特点 计算速度快强随机分布性&#xff0…

由浅到深认识Java语言(21):Math类

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

Spring IoC DI(1)

IoC & DI入门 Spring 通过前面的学习, 我们知道了Spring是一个开源框架, 它让我们的开发更加简单. 它支持广泛的应用场景, 有着活跃且庞大的社区, 这就是Spring能够长久不衰的原因. 但是这个概念还是比较抽象. 可以用更具体的话描述Spring, 那就是: Spring是包含了众多…

HAL STM32G4内部运放的使用

HAL STM32G4内部运放的使用 &#x1f4cd;相关篇《HAL STM32G4 ADC手动触发采集各种滤波算法实现》&#x1f388;《HAL STM32G4 TIM1 3路PWM互补输出VOFA波形演示》 ✨继欧拉电子无刷电机驱动相关视频学习&#xff0c;STM32G4内部运放的使用。主要是为了采集无刷电机&#xff0…

《深入浅出LLM 》(二):大模型基础知识

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

C语言栈和队列(个人笔记)

栈和队列 栈1.1栈的概念和结构1.2栈的实现 队列2.1队列的概念及结构2.2队列的实现2.3循环队列 栈和队列笔试题3.1[有效的括号](https://leetcode.cn/problems/valid-parentheses/submissions/516297357/)3.2[用队列实现栈](https://leetcode.cn/problems/implement-stack-using…

c盘清理软件绿色免安装版老电脑的福音

家里有一台老电脑笔记本&#xff0c;10年前的产品了&#xff0c;内存也不大&#xff0c;只有2G&#xff0c;安装360后&#xff0c;就卡的不行了&#xff0c;安装他的目的其实就是为了定期清理一下C盘空间&#xff0c;为了解决这个问题&#xff0c;于是做了一下研究&#xff0c;…

【Java常用API】正则表达式练习

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

安卓转鸿蒙竟如此丝滑

随着鸿蒙的爆火&#xff0c;大家都想知道鸿蒙能不能搞&#xff1f; 相信大家搞开发的&#xff0c;都多多少少的了解过鸿蒙。近几个月鸿蒙的大动作也不少&#xff0c;如&#xff1a;重庆市近20个垂域应用与鸿蒙原生合作、深圳制定鸿蒙《行动计划》、阿里再次与鸿蒙展开合作&…

文件操作3

随机读写数据文件 一、随机读写原理 在我们写数据时&#xff0c;有一个光标不断的在随着新写入的数据往后移动&#xff1b; 而读数据时&#xff0c;也有一个看不见光标&#xff0c;随着已经读完的数据&#xff0c;往后移动 这里的文件读写位置标记——可以想象成图形界面里的…

计算机程序的编译和链接

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

代码随想录第20天| 654.最大二叉树 617.合并二叉树

654.最大二叉树 654. 最大二叉树 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 又是构造二叉树&#xff0c;又有很多坑&#xff01;| LeetCode&#xff1a;654.最大二叉树_哔哩哔哩_bilibili 给定一个不重复的整数数组 nums 。 最大二叉树 可以…

python+selenium做ui自动化测试用法必会

一、前言 大家都知道&#xff0c;基于Web端的测试的基础框架是需要Selenium做主要支撑的&#xff0c;这里边给大家介绍下Web测试核心之基于Python的Selenium Selenium是用于测试Web应用程序用户界面(UI)的常用框架。它是一款用于运行端到端功能测试的超强工具。您可以使用多个编…

ExperimentalWarning: The http2 module is an experimental API.

错误提示 Node.js:ExperimentalWarning: The fs.promises API is experimental原因是node的版本不是最新的&#xff0c;而在项目引入的模块是最新的&#xff0c;node.js的版本低于模块的版本&#xff1a; 解决方法: 1、升级版本 npm install -g npm 更新npm到最新版 npm ins…

MyBatis3源码深度解析(二十一)动态SQL实现原理(二)动态SQL解析过程、#{}和${}的区别

文章目录 前言8.5 动态SQL解析过程8.5.1 SQL配置转换为SqlSource对象8.5.2 SqlSource转换为静态SQL语句 8.6 #{}和${}的区别8.7 小结 前言 在【MyBatis3源码深度解析(二十)动态SQL实现原理(一)动态SQL的核心组件】中研究了MyBatis动态SQL相关的组件&#xff0c;如SqlSource用于…

vue.js制作学习计划表案例

通俗易懂&#xff0c;完成“学习计划表”用于对学习计划进行管理&#xff0c;包括对学习计划进行添加、删除、修改等操作。 一. 初始页面效果展示 二.添加学习计划页面效果展示 三.修改学习计划完成状态的页面效果展示 四.删除学习计划 当学习计划处于“已完成”状态时&…

Linux基础-Makefile

目录 一、Make简介 二、Makefile基本结构 示例&#xff1a; 补充(Makefile)&#xff1a; 伪目标&#xff1a; 三、创建和使用变量 变量定义的方式&#xff1a; 简单方式&#xff1a; 递归方式&#xff1a; 用?定义变量 为变量添加值 预定义变量 例 自动变量 例…