From f54b5045c75441a0f4d940d2b62fcab07e43bae3 Mon Sep 17 00:00:00 2001 From: chongtiantian Date: Mon, 29 Apr 2024 17:58:07 +0800 Subject: [PATCH] =?UTF-8?q?ImageKnife=E6=8E=A7=E5=88=B6=E5=8F=AF=E8=A7=86?= =?UTF-8?q?=E5=8C=96=E5=8C=BA=E5=9F=9F=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: chongtiantian --- CHANGELOG.md | 1 + .../ets/pages/imageknifeTestCaseIndex.ets | 4 + entry/src/main/ets/pages/testVisiblePage.ets | 263 ++++++++++++++++++ .../resources/base/profile/main_pages.json | 1 + .../ets/components/imageknife/ImageKnife.ets | 38 ++- .../imageknife/ImageKnifeComponent.ets | 80 ++++-- .../components/imageknife/RequestOption.ets | 9 + 7 files changed, 375 insertions(+), 21 deletions(-) create mode 100644 entry/src/main/ets/pages/testVisiblePage.ets diff --git a/CHANGELOG.md b/CHANGELOG.md index de3dadb..3f386bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 2.2.0-rc.2 - ImageKnife支持heic图片修改demo,按钮控制组件是否展示 +- ImageKnife控制可视化区域图片 ## 2.2.0-rc.1 - 修改ImageKnife跳过网络,点击默认,图片没有传入宽高,无显示bug diff --git a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets index a951647..68c7303 100644 --- a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets +++ b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets @@ -122,6 +122,10 @@ struct IndexFunctionDemo { .height(60).backgroundColor(Color.Pink) Text("测试复用场景").fontSize(15) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("可视区加载") + .onClick(() => { + router.pushUrl({ url: "pages/testVisiblePage" }); + }).margin({ top: 5, left: 3 }) Button("懒加载复用列表") .onClick(() => { console.log("测试一级内存缓存") diff --git a/entry/src/main/ets/pages/testVisiblePage.ets b/entry/src/main/ets/pages/testVisiblePage.ets new file mode 100644 index 0000000..64384f7 --- /dev/null +++ b/entry/src/main/ets/pages/testVisiblePage.ets @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ImageKnifeComponent } from '@ohos/libraryimageknife'; + +class CommonDataSource implements IDataSource { + private dataArray: T[] = [] + private listeners: DataChangeListener[] = [] + + constructor(element: []) { + this.dataArray = element + } + + public getData(index: number) { + return this.dataArray[index] + } + + public totalCount(): number { + return this.dataArray.length + } + + public addData(index: number, data: T[]): void { + this.dataArray = this.dataArray.concat(data) + this.notifyDataAdd(index) + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener) + } + } + + notifyDataAdd(index: number): void { + this.listeners.forEach((listener: DataChangeListener) => { + listener.onDataAdd(index) + }) + } +} + +@Entry +@Component +struct TestVisiblePage { + @State currentScene: string = 'LazyForEach'; + @State hotCommendList: CommonDataSource = new CommonDataSource([]); + @State data: Array = [ + "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg", + "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg", + "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg", + "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg", + "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg", + "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg", + "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg", + "http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg", + "http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg", + "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg", + "http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg", + "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", + 'https://img-blog.csdnimg.cn/20191215043500229.png', + 'https://img-blog.csdn.net/20140514114029140', + 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/R9aT7lpEEVxawo4.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/1V6c63lKLGPlKVo.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/2NxCo49xAB1L96K.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/P6gH3pWBGw7L6dD.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/MKosgAWo5VKpo9Z.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/pA2S9lvNpMY4X3N.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/69MiA9VxKdkzjWR.png!thumb-w321-webp75", + "https://material-center-pre.meitudata.com/material/image/6228901fd8ddd6350.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/P98i3gdgDw3Rmx5.png!thumb-w321-webp75", + "https://stage.meitudata.com/public/creator/ed70a3c696c8e7b.jpg!thumb-w321-webp75", + "https://material-center-pre.meitudata.com/material/image/6194a57b5b9ef7678.jpg!thumb-w321-webp75", + "https://material-center-pre.meitudata.com/material/image/6189f29b48f165954.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/0lZCW9BrDgMroLL.jpeg!thumb-w321-webp75", + "https://xximg1.meitudata.com/V2jTkoYa96.jpeg!thumb-w321-webp75", + "http://xximg2.meitudata.com/Z9DCJpkB2l.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/zwdte8R2e5KMMmm.jpeg!thumb-w321-webp75", + "https://xximg1.meitudata.com/mlahyxNxjN.jpeg!thumb-w321-webp75", + "https://xximg1.meitudata.com/8OkUwBympV.jpeg!thumb-w321-webp75", + "https://xximg1.meitudata.com/9nzUydyWeB.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/R9aT7lpEEVxawo4.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/Ymju0r3deAl7xoJ.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/8zPcB0y4vdreG1d.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/1V6c63lKLGPlKVo.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/Z9dtor442OY76KV.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/2NxCo49xAB1L96K.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/xxtool-pre/material/P6gH3pWBGw7L6dD.jpeg!thumb-w321-webp75", + "https://material-center-pre.meitudata.com/material/image/6228901fd8ddd6350.jpeg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/deRP83dkdlR4.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/rPJ1vKjJY6jz.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/z8K3P249ZmVW.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/e4xlVkl0BzMy.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/B6MleZrWeMvj.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/B6MleZ1ae5Ry.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/EyvzkoPgakDL.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/3zVRo1E16vZG.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/3zVRo1EdvZ0W.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/1mLMv1kd2BLZ.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/8NXRMzE019aB.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/0XDRo7xdPkVx.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/V06dg1RJ8pDr.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/2p5Ro1VDZvxR.png!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/1mLMWyxNVMAe.jpg!thumb-w321-webp75", + "https://xxtool-release.zone1.meitudata.com/7d8RoA7DXYB9.jpg!thumb-w321-webp75", + "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg", + "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg", + "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg", + "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg", + "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg", + "http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg", + "http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg", + "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg", + "http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg", + "http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg", + "http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg", + ] + private listScroller: Scroller = new Scroller(); + + + aboutToAppear() { + this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data) + } + + build() { + Column() { + Flex(){ + Button('懒加载场景').flexGrow(1).height(40).onClick(() => { + this.currentScene = 'LazyForEach'; + this.listScroller.scrollToIndex(0); + }) + Button('懒加载+复用场景').flexGrow(1).height(40).onClick(() => { + this.currentScene = 'ReuseAndLazyForEach'; + this.listScroller.scrollToIndex(0); + }) + Button('其他场景').flexGrow(1).height(40).onClick(() => { + this.currentScene = 'ForEach'; + this.listScroller.scrollToIndex(0); + }) + }.padding({top: 10, bottom: 10}) + List({ space: 20, scroller: this.listScroller }) { + if(this.currentScene == 'LazyForEach') { + this.renderLazyForEachComponent(); + } else if (this.currentScene == 'ReuseAndLazyForEach') { + this.renderReuseComponent(); + } else { + this.renderForEachComponent(); + } + } + + .width("100%") + .height("100%") + .backgroundColor(0xFAEEE0) + }.width("100%").height("100%") + } + + @Builder + renderLazyForEachComponent () { + LazyForEach(this.hotCommendList, (item: string, index: number) => { + ListItem() { + MyComponent({ url: item, index: index + '' }).width("100%").height("100%") + }.width(200).height(200).backgroundColor(Color.Orange) + }) + } + + @Builder + renderReuseComponent () { + LazyForEach(this.hotCommendList, (item: string, index: number) => { + ListItem() { + ReuseComponent({ url: item, index: index + '' }).width("100%").height("100%") + }.width(200).height(200).backgroundColor(Color.Orange) + }) + } + + @Builder + renderForEachComponent () { + ForEach(this.data, (item: string, index: number) => { + ListItem() { + MyComponent({ url: item, index: index + '' }).width("100%").height("100%") + }.width(200).height(200).backgroundColor(Color.Orange) + }) + } +} + + + +// 没有复用的组件 +@Component +struct MyComponent { + @Prop url: string = ""; + @Prop index: string = '0'; + + build() { + Column() { + Flex({ direction: FlexDirection.Column}) { + Text(this.index).fontSize(18).fontColor(Color.White) + ImageKnifeComponent({ + imageKnifeOption:{ + loadSrc: this.url, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + } + }).height(150) + } + }.width("100%").height("100%") + } +} + +// 复用组件 +@Reusable +@Component +struct ReuseComponent { + @Prop url: string = ""; + @Prop index: string = '0'; + + aboutToReuse(params: Record) { + this.url = params.url; + this.index = params.index; + } + + build() { + Column() { + Flex({ direction: FlexDirection.Column}) { + Text(this.index).fontSize(18).fontColor(Color.White) + ImageKnifeComponent({ + imageKnifeOption:{ + loadSrc: this.url, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + } + }).height(150) + } + }.width("100%").height("100%") + } +} diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 3be410f..affb988 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -48,6 +48,7 @@ "pages/testImageKnifeAutoWidthPage", "pages/testImageKnifeAutoHeightPage", "pages/testPriorityComponent", + "pages/testVisiblePage", "pages/testReusePhotoPage", "pages/testImageKnifeCache", "pages/webpImageTestPage", diff --git a/library/src/main/ets/components/imageknife/ImageKnife.ets b/library/src/main/ets/components/imageknife/ImageKnife.ets index 3e784a1..040ab4d 100644 --- a/library/src/main/ets/components/imageknife/ImageKnife.ets +++ b/library/src/main/ets/components/imageknife/ImageKnife.ets @@ -16,7 +16,7 @@ import { DiskLruCache } from "../cache/DiskLruCache" import { EngineKeyFactories } from "../cache/key/EngineKeyFactories" import { EngineKeyInterface } from "../cache/key/EngineKeyInterface" -import { CacheType, RequestOption, Size } from "../imageknife/RequestOption" +import { CacheType, RequestOption, Size, ImageKnifeRequestState } from "../imageknife/RequestOption"; import { AsyncCallback } from "../imageknife/interface/AsyncCallback" import { PlaceHolderManager } from "../imageknife/holder/PlaceHolderManager" import { RetryHolderManager } from "../imageknife/holder/RetryHolderManager" @@ -268,6 +268,7 @@ export class ImageKnife { // 删除 请求 remove(uuid: string) { + LogUtil.log('VISIBLE: remove request ' + uuid); this.executingJobMap.remove(uuid); } @@ -495,6 +496,7 @@ export class ImageKnife { // 删除执行结束的running removeRunning(request: RequestOption) { + LogUtil.log('VISIBLE: removeRunning ' + request.uuid + '|' + request.loadSrc); if (!this.isPaused) { //不暂停则继续加载 this.executingJobMap.remove(request.uuid); @@ -504,6 +506,8 @@ export class ImageKnife { // 启动新线程 去磁盘取 去网络取 private loadCacheManager(request: RequestOption) { + LogUtil.log("VISIBLE: loadCacheManager start uuid : " + request.uuid + '|' + request.requestState + " url : " + request.loadSrc); + if (request.requestState === ImageKnifeRequestState.DESTROY) return; if (this.keyNotEmpty(request)) { if (this.executingJobMap.length > this.maxRequests) { this.jobQueue.add(request); @@ -621,11 +625,15 @@ export class ImageKnife { request.errorholderOnComplete(errorholderCacheKey); return; } else if (usageType == Constants.MAIN_HOLDER && mainCache) { - LogUtil.info("imageknife load mainsource from MemoryCache") mainCache.waitSaveDisk = false; let requestList: List | undefined = this.executingJobMap.get(request.uuid); + LogUtil.info("VISIBLE: imageknife load mainsource from MemoryCache. requestList?.length: " + requestList?.length); + // 组件被销毁会删除请求,因此requestList可能是undefined if(requestList != undefined) { requestList.forEach((requestOption: RequestOption)=>{ + if (requestOption.requestState === ImageKnifeRequestState.PROGRESS) { + requestOption.requestState = ImageKnifeRequestState.COMPLETE; + } requestOption.loadComplete(mainCache as ImageKnifeData); }) } @@ -675,8 +683,13 @@ export class ImageKnife { if ((typeof (data as PixelMap).isEditable) == 'boolean') { let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap); let requestList: List | undefined = this.executingJobMap.get(request.uuid) + LogUtil.info("VISIBLE: taskpool execute done. data as PixelMap: " + requestList?.length); + // 组件被销毁会删除请求,因此requestList可能是undefined if(requestList != undefined) { requestList.forEach((requestOption: RequestOption)=>{ + if (requestOption.requestState === ImageKnifeRequestState.PROGRESS) { + requestOption.requestState = ImageKnifeRequestState.COMPLETE; + } requestOption.loadComplete(imageKnifeData); }) } @@ -684,17 +697,30 @@ export class ImageKnife { } else if ((data as GIFFrame[]).length > 0) { let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data as GIFFrame[]); let requestList: List | undefined = this.executingJobMap.get(request.uuid); + LogUtil.info("VISIBLE: taskpool execute done. data as GIFFrame: " + requestList?.length); + // 组件被销毁会删除请求,因此requestList可能是undefined if(requestList != undefined) { requestList.forEach((requestOption: RequestOption)=>{ + if (requestOption.requestState === ImageKnifeRequestState.PROGRESS) { + requestOption.requestState = ImageKnifeRequestState.COMPLETE; + } requestOption.loadComplete(imageKnifeData); }) } this.memoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData); } else { + if (request.requestState === ImageKnifeRequestState.PROGRESS) { + request.requestState = ImageKnifeRequestState.ERROR; + } + LogUtil.info("VISIBLE: MAIN_HOLDER loadError. request: " + request.uuid + '|' + request.requestState + '|' + request.loadSrc); request.loadError("request resources error") } } }).catch((err: BusinessError | string) => { + if (request.requestState === ImageKnifeRequestState.PROGRESS) { + request.requestState = ImageKnifeRequestState.ERROR; + } + LogUtil.info("VISIBLE: taskpool response Error. request: " + request.uuid + '|' + request.requestState + '|' + request.loadSrc); request.loadError(err) }) } @@ -758,8 +784,14 @@ export class ImageKnife { // 分发下一个任务 dispatchNextJob() { let request: RequestOption | undefined = this.jobQueue.pop(); + LogUtil.log('VISIBLE: 出队列 . ' + request?.uuid + '|' + request?.requestState + '|' + request?.loadSrc); if (request != undefined) { - this.loadCacheManager(request); + // 出队列的时候,如果已经销毁就不执行loadCacheManager + if(request.requestState !== ImageKnifeRequestState.DESTROY) { + this.loadCacheManager(request); + } else { + this.dispatchNextJob(); + } } } diff --git a/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets b/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets index 11d288a..caf12cf 100644 --- a/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets +++ b/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets @@ -16,7 +16,7 @@ import { ImageKnifeOption } from '../imageknife/ImageKnifeOption' import { ImageKnifeGlobal } from '../imageknife/ImageKnifeGlobal' import { TransformType } from '../imageknife/transform/TransformType' -import { DetachFromLayout, RequestOption, Size } from '../imageknife/RequestOption' +import { DetachFromLayout, ImageKnifeRequestState, RequestOption, Size } from '../imageknife/RequestOption'; import { ImageKnifeData } from '../imageknife/ImageKnifeData' import { GIFFrame } from '../imageknife/utils/gif/GIFFrame' import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle' @@ -28,6 +28,7 @@ import componentUtils from '@ohos.arkui.componentUtils' import inspector from '@ohos.arkui.inspector' import util from '@ohos.util' import { ImageKnifeDrawFactory } from './ImageKnifeDrawFactory' +import { ImageKnife } from './ImageKnife'; interface KeyCanvas { keyId:string @@ -113,6 +114,9 @@ export struct ImageKnifeComponent { height: 0.01 } + @State request: RequestOption | undefined = undefined; + drawMainSourceSuccess: boolean = false; + build() { Canvas(this.context) .key(this.keyCanvas.keyId) @@ -157,9 +161,18 @@ export struct ImageKnifeComponent { } watchImageKnifeOption() { - LogUtil.log('ImageKnifeComponent watchImageKnifeOption is happened!') - this.lastSrc = this.imageKnifeOption.loadSrc - this.whetherWaitSize(); + // 如果loadSrc改变 或 资源是gif且是多帧 request重新初始化 + LogUtil.log('VISIBLE: watchImageKnifeOption! ' + this.imageKnifeOption.loadSrc); + if((this.lastSrc !== this.imageKnifeOption.loadSrc) || + (this.renderFrames_frames && this.renderFrames_frames.length > 1)) { + if (this.request !== undefined) { + this.request.requestState = ImageKnifeRequestState.DESTROY; + this.request = undefined; + } + this.request = new RequestOption(); + this.lastSrc = this.imageKnifeOption.loadSrc; + this.whetherWaitSize(); + } } /** @@ -203,7 +216,7 @@ export struct ImageKnifeComponent { configNecessary(request: RequestOption) { request.load(this.imageKnifeOption.loadSrc) .addListener({ callback: (err:BusinessError|string, data:ImageKnifeData) => { - LogUtil.log('ImageKnifeComponent request.load callback') + LogUtil.log('VISIBLE: ImageKnifeComponent request.load callback, err: ' + err); if(data.isGIFFrame()) { this.isGif = true } else { @@ -211,7 +224,11 @@ export struct ImageKnifeComponent { } if(this.lastSrc !== request.loadSrc && this.lastSrc !== ""){} else { - this.runNextFunction(this.displayMainSource,data); + // 组件 没有被销毁 执行渲染逻辑 + LogUtil.log('VISIBLE: request.load callback, request: ' + this.request?.requestState + '|' + this.request?.loadSrc) + if (this.request?.requestState !== ImageKnifeRequestState.DESTROY){ + this.runNextFunction(this.displayMainSource,data); + } } return false; } @@ -344,15 +361,19 @@ export struct ImageKnifeComponent { return } this.resetGifData() - let request = new RequestOption(); - this.detachFromLayout = request.detachFromLayout; - this.configNecessary(request); - this.configCacheStrategy(request); - this.configDisplay(request); - this.configHspContext(request); - this.configRenderGpu(request); - if(ImageKnifeGlobal.getInstance().getImageKnife()!=undefined) { - ImageKnifeGlobal.getInstance().getImageKnife()?.call(request); + if(this.request == undefined) { + this.request = new RequestOption(); + this.lastSrc = this.imageKnifeOption.loadSrc; + } + this.detachFromLayout = this.request.detachFromLayout; + this.configNecessary(this.request); + this.configCacheStrategy(this.request); + this.configDisplay(this.request); + this.configHspContext(this.request); + this.configRenderGpu(this.request); + let imageKnife: ImageKnife | undefined = ImageKnifeGlobal?.getInstance()?.getImageKnife(); + if(imageKnife != undefined) { + imageKnife.call(this.request); } } @@ -507,6 +528,8 @@ export struct ImageKnifeComponent { // } // getImageInfo异步 data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { + // 如果主图绘制完成 则不绘制占位图 + if(this.drawMainSourceSuccess) return; LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height) let scaleType = (typeof imageKnifeOption.placeholderScaleType == 'number') ? imageKnifeOption.placeholderScaleType : ScaleType.FIT_CENTER context.save(); @@ -615,7 +638,8 @@ export struct ImageKnifeComponent { } ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0) context.restore(); - LogUtil.log('ImageKnifeComponent default drawMainSource end!') + this.drawMainSourceSuccess = true; + LogUtil.log('VISIBLE: ImageKnifeComponent default drawMainSource end!'); }) if (data.drawPixelMap != undefined) { data.drawPixelMap.isShowOnComponent = true; @@ -626,6 +650,8 @@ export struct ImageKnifeComponent { data.drawGIFFrame.isShowOnComponent = true this.detachFromLayoutGIF = data.drawGIFFrame.detachFromLayoutGIF this.drawGIFFrame(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId) + this.drawMainSourceSuccess = true; + LogUtil.log('VISIBLE: ImageKnifeComponent default drawMainSource gif end!' + this.request?.loadSrc); } } } @@ -722,13 +748,21 @@ export struct ImageKnifeComponent { } } aboutToRecycle(){ + LogUtil.log('VISIBLE: Recycle happened! Component destroyed.'); this.resetGifData() + if(this.detachFromLayout != undefined){ + this.detachFromLayout.detach(); + } + this.updateResetRequest(); } aboutToReuse(params: ESObject) { + LogUtil.log('VISIBLE: Reuse happened!'); this.context.clearRect(0,0,this.context.width,this.context.height) + // watch方法会触发两次,第二次触发不会执行加载逻辑,reuse比watch晚,因此需要手动在此处触发加载逻辑 + this.whetherWaitSize(); } aboutToAppear() { - LogUtil.log('ImageKnifeComponent aboutToAppear happened!') + LogUtil.log('VISIBLE: ImageKnifeComponent aboutToAppear happened!') this.canvasHasReady = false; this.whetherWaitSize(true); @@ -736,7 +770,7 @@ export struct ImageKnifeComponent { } aboutToDisappear() { - LogUtil.log('ImageKnifeComponent aboutToDisappear happened!') + LogUtil.log('VISIBLE: ImageKnifeComponent aboutToDisappear happened!') if(this.detachFromLayout != undefined){ this.detachFromLayout.detach(); } @@ -750,6 +784,16 @@ export struct ImageKnifeComponent { this.resetGifData(); } this.listener.off("layout",this.onLayoutComplete) + this.updateResetRequest(); + } + + // 更新并重置request + updateResetRequest() { + if(this.request != undefined) { + LogUtil.log('VISIBLE: 更新并重置request' + this.request.uuid + '|' + this.request.loadSrc); + this.request.requestState = ImageKnifeRequestState.DESTROY; + this.request = undefined; + } } onPageShow() { diff --git a/library/src/main/ets/components/imageknife/RequestOption.ets b/library/src/main/ets/components/imageknife/RequestOption.ets index 0d2b0f9..85a33d0 100644 --- a/library/src/main/ets/components/imageknife/RequestOption.ets +++ b/library/src/main/ets/components/imageknife/RequestOption.ets @@ -66,6 +66,13 @@ export interface Size { height: number } +export enum ImageKnifeRequestState { + PROGRESS, + COMPLETE, + ERROR, + DESTROY +} + export enum CacheType { Default, //缓存 @@ -179,6 +186,8 @@ export class RequestOption { } // module资源的需要当前的module context moduleContext?: common.UIAbilityContext = undefined; + // 请求状态 + requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS constructor() { // 初始化全局监听