diff --git a/CHANGELOG.md b/CHANGELOG.md index 794a2f7..0e043d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,17 @@ - -## 3.1.1-rc.0 -- 重构代码:抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中,降低函数复杂度 - -## 3.1.0 +## 3.0.2 +- ImageKnifeAnimatorComponent新增开始、结束、暂停的回调事件 +- 文件缓存数量负数和超过INT最大值时默认为INT最大值 +- 修复宽高不等svg图片显示有毛边 - 部分静态webp图片有delay属性导致识别成动图,改用getFrameCount识别 - 修复加载错误图后未去请求排队队列中的请求 - 子线程本地Resource参数类型转换成number - 修改使用hilog记录日志,默认打开debug级别的日志 -- file格式图片,fd同步close - 解码pixelMap默认不可编辑,图形变化可编辑 - 修改网络请求超时设置 +- 重构代码:抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中,降低函数复杂度 -## 3.1.0-rc.2 -- 修复宽高不等svg图片显示有毛边 - -## 3.1.0-rc.1 -- ImageKnifeAnimatorComponent新增开始、结束、暂停的回调事件 -- 文件缓存数量负数和超过INT最大值时默认为INT最大值 - -## 3.1.0-rc.0 -- ComponentV2装饰器适配 -- imageKnifeOption={...}用法改为new ImageKnifeOption({...}) -- animatorOption={...}用法改为new AnimatorOption({...}) +## 3.0.2-rc.0 +- FileUtil.readFile接口和file格式图片同步关闭fd ## 3.0.1 - 修复animatorOption属性设置初始化值失效 diff --git a/README.md b/README.md index bf787e0..3f50768 100644 --- a/README.md +++ b/README.md @@ -1,228 +1,229 @@ # ImageKnife -ImageKnife is a specially crafted image loading and caching library for OpenHarmony, optimized for efficiency, lightness, and simplicity. +**专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单。** -## Introduction +## 简介 -This project is a self-developed version for OpenHarmony, inspired by the open-source [Glide](https://github.com/bumptech/glide) library. It sports the following features: +本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本: -- Customizable memory cache strategy with adjustable cache size (default LRU) -- Disk L2 cache for downloaded images -- Custom implementation for image acquisition and network downloading -- Listening for progress of network downloads through callbacks -- Image options for borders and rounded corners -- Image scaling with **objectFit**, including auto-adapting height -- Image scaling through transformation -- Concurrent request management with priority queuing -- No requests made for images whose lifecycle has been destroyed -- Custom cache keys -- Custom HTTP request headers -- **writeCacheStrategy** for controlling cache storage (memory or file) -- Preloading images with **preLoadCache** -- Loading images exclusively from cache with **onlyRetrieveFromCache** -- Support for image transformations such as blurring and highlighting +- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)。 +- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。 +- 支持自定义实现图片获取/网络下载 +- 支持监听网络下载回调进度 +- 继承Image的能力,支持option传入border,设置边框,圆角 +- 继承Image的能力,支持option传入objectFit设置图片缩放,包括objectFit为auto时根据图片自适应高度 +- 支持通过设置transform缩放图片 +- 并发请求数量,支持请求排队队列的优先级 +- 支持生命周期已销毁的图片,不再发起请求 +- 自定义缓存key +- 自定义http网络请求头 +- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存) +- 支持preLoadCache预加载图片 +- 支持onlyRetrieveFromCache仅用缓存加载 +- 支持使用一个或多个图片变换,如模糊,高亮等 -Planned features: +待实现特性 -- Memory downsampling optimization to save memory usage -- Support for custom image decoding +- gif/webp动图显示与控制 +- 内存降采样优化,节约内存的占用 +- 支持自定义图片解码 -Note: The 3.x version has been significantly restructured from the 2.x version, mainly in the following aspects: +注意:3.x版本相对2.x版本做了重大的重构,主要体现在: -- Use of the **Image** component instead of the **Canvas** component for rendering -- Refactored dispatch logic to control the number of concurrent requests and support priority in request queuing -- Support for custom memory cache strategies and sizes through **initMemoryCache** -- Support for custom implementation of image acquisition/network downloading through options +- 使用Image组件代替Canvas组件渲染 +- 重构Dispatch分发逻辑,支持控制并发请求数,支持请求排队队列的优先级 +- 支持通过initMemoryCache自定义策略内存缓存策略和大小 +- 支持option自定义实现图片获取/网络下载 -Therefore, there are some differences in APIs and capabilities, which mainly include the following: +因此API及能力上,目前有部分差异,主要体现在: -- The **drawLifeCycle** API is not supported; images are drawn manually through the canvas. -- In the new version, parameters such as **mainScaleType** and **border** are consistent with the system **Image** component. -- GIF/WebP animation playback and control (implemented by **ImageAnimator**). -- Anti-aliasing related parameters. +- 不支持drawLifeCycle接口,通过canvas自会图片 +- mainScaleType,border等参数,新版本与系统Image保持一致 +- gif/webp动图播放与控制 +- 抗锯齿相关参数 -## How to Install +## 下载安装 ``` ohpm install @ohos/imageknife -// If file caching is required, initialize the file cache in advance. +// 如果需要用文件缓存,需要提前初始化文件缓存 await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024) ``` -## How to Use +## 使用说明 -#### 1. Displaying a Local Resource Image +#### 1.显示本地资源图片 ``` ImageKnifeComponent({ - ImageKnifeOption: new ImageKnifeOption({ + ImageKnifeOption: { loadSrc: $r("app.media.app_icon"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Auto - }) + } }).width(100).height(100) ``` -#### 2. Displaying a File from Local Context Files +#### 2.显示本地context files下文件 ``` ImageKnifeComponent({ - ImageKnifeOption: new ImageKnifeOption({ + ImageKnifeOption: { loadSrc: this.localFile, placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Auto - }) + } }).width(100).height(100) ``` -#### 3. Displaying a Network Image +#### 3.显示网络图片 ``` ImageKnifeComponent({ - ImageKnifeOption: new ImageKnifeOption({ + ImageKnifeOption: { loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Auto - }) + } }).width(100).height(100) ``` -#### 4. Downloading an Image with Custom Options +#### 4.自定义下载图片 ``` ImageKnifeComponent({ - ImageKnifeOption: new ImageKnifeOption({ + ImageKnifeOption: { loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Auto, customGetImage: custom - }) + } }).width(100).height(100) -// Custom implementation of the image acquisition method, such as custom network download。 +// 自定义实现图片获取方法,如自定义网络下载 @Concurrent async function custom(context: Context, src: string | PixelMap | Resource): Promise { - console.info("ImageKnife:: custom download: " + src) - // Example of hardcoding to read from a local file. You can also request a network image. + console.info("ImageKnife:: custom download:" + src) + // 举例写死从本地文件读取,也可以自己请求网络图片 return context.resourceManager.getMediaContentSync($r("app.media.bb").id).buffer as ArrayBuffer } ``` -#### 5. Listening for Network Download Progress +#### 5.监听网络下载进度 ``` ImageKnifeComponent({ - ImageKnifeOption: new ImageKnifeOption({ + ImageKnifeOption: { loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)} - }) + } }).width(100).height(100) ``` -#### 6. Setting Border Options +#### 6.支持option传入border,设置边框,圆角 ``` -ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +ImageKnifeComponent({ ImageKnifeOption: { loadSrc: $r("app.media.rabbit"), border: {radius:50} - }) + } }).width(100).height(100) ``` -#### 7. Setting Image Transformation Options +#### 7.支持option图片变换 ``` -ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +ImageKnifeComponent({ ImageKnifeOption: { loadSrc: $r("app.media.rabbit"), border: {radius:50}, transformation: new BlurTransformation(3) - }) + } }).width(100).height(100) ``` -Multiple combined transformation usages: +多种组合变换用法 ``` let transformations: collections.Array = new collections.Array(); transformations.push(new BlurTransformation(5)); transformations.push(new BrightnessTransformation(0.2)); ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + { loadSrc: $r('app.media.pngSample'), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Contain, - border: { radius: { topLeft: 50, bottomRight: 50 } }, // Rounded corner settings - transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group -}) + border: { radius: { topLeft: 50, bottomRight: 50 } }, // 圆角设置 + transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组 +} }).width(300) .height(300) - .rotate ({angle: 90}) // Rotate by 90 degrees. - .contrast(12) // Contrast filter + .rotate({ angle: 90 }) // 旋转90度 + .contrast(12) // 对比度滤波器 ``` -Other transformation-related properties can be stacked to achieve combined transformation effects. +其他变换相关属性,可叠加实现组合变换效果 -Example of circular cropping transformation: +圆形裁剪变换示例 ``` -ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( +ImageKnifeComponent({ ImageKnifeOption: { loadSrc: $r('app.media.pngSample'), objectFit: ImageFit.Cover, border: { radius: 150 } -}) +} }).width(300) .height(300) ``` -Example of Circular cropping with border transformation: +圆形裁剪带边框变换示例 ``` -ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( +ImageKnifeComponent({ ImageKnifeOption: { loadSrc: $r('app.media.pngSample'), objectFit: ImageFit.Cover, border: { radius: 150, color: Color.Red, width: 5 } -}) +} }).width(300) .height(300) ``` -Example of contrast filtering transformation: +对比度滤波变换示例 ``` ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: $r('app.media.pngSample') - }) + } }).width(300) .height(300) .contrast(12) ``` -Example of rotation transformation: +旋转变换示例 ``` ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: $r('app.media.pngSample') - }) + } }).width(300) .height(300) .rotate({angle:90}) .backgroundColor(Color.Pink) ``` -#### 8. Listening for Image Loading Success and Failure +#### 8.监听图片加载成功与失败 ``` -ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( +ImageKnifeComponent({ ImageKnifeOption: { loadSrc: $r("app.media.rabbit"), onLoadListener:{ @@ -241,135 +242,128 @@ ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( console.info(err) } } - }) + } }).width(100).height(100) ``` -#### 9. Use of syncLoad -**syncLoad** sets whether to load the image synchronously. By default, the image is loaded asynchronously. When loading a small image, you are advised to set **syncLoad** to **true** so that the image loading can be quickly completed on the main thread. +#### 9.ImageKnifeComponent - syncLoad +设置是否同步加载图片,默认是异步加载。建议加载尺寸较小的本地图片时将syncLoad设为true,因为耗时较短,在主线程上执行即可 ``` ImageKnifeComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:$r("app.media.pngSample"), placeholderSrc:$r("app.media.loading") - }),syncLoad:true + },syncLoad:true }) ``` -#### 10. Use of ImageKnifeAnimatorComponent +#### 10.ImageKnifeAnimatorComponent 示例 ``` ImageKnifeAnimatorComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }),animatorOption:this.animatorOption + },animatorOption:this.animatorOption }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30}) ``` -#### Reuse Scenario -Clear the component content in the **aboutToRecycle** lifecycle and trigger image loading through watch observeration. -## Available APIs -### ImageKnife -| Component | Parameter | Description | -| --------------------------- | -------------------------------- | ------------ | -| ImageKnifeComponent | ImageKnifeOption | Image display component.| -| ImageKnifeAnimatorComponent | ImageKnifeOption, AnimatorOption| Animated image control component.| +## 接口说明 +### ImageKnife组件 +| 组件名称 | 入参内容 | 功能简介 | +|-----------------------------|---------------------------------|--------| +| ImageKnifeComponent | ImageKnifeOption | 图片显示组件 | +| ImageKnifeAnimatorComponent | ImageKnifeOption、AnimatorOption | 动图控制组件 | -### AnimatorOption -| Parameter | Type | Description | -| ---------- | --------------- | ---------------------------------------- | -| state | AnimationStatus | Playback status. Optional. | -| iterations | number | Number of playback times. Optional. | -| reverse | boolean | Playback order. Optional. | -| onStart | ()=>void | Triggered when the animation starts. Optional. | -| onFinish | ()=>void | Triggered when the animation finishes or stops. Optional.| -| onPause | ()=>void | Triggered when the animation pauses. Optional. | -| onCancel | ()=>void | Triggered when the animation is canceled, that is, when it is reset to its initial state. Optional. | -| onRepeat | ()=>void | Triggered when the animation repeats. Optional. | +### AnimatorOption参数列表 +| 参数名称 | 入参内容 | 功能简介 | +|-----------------------|-------------------------------------------------------|----------| +| state | AnimationStatus | 播放状态(可选) | +| iterations | number | 播放次数(可选) | +| reverse | boolean | 播放顺序(可选) | -### ImageKnifeOption +### ImageKnifeOption参数列表 -| Parameter | Type | Description | -| --------------------- | ----------------------------------------------------- | ------------------------------ | -| loadSrc | string, PixelMap, Resource | Main image. | -| placeholderSrc | PixelMap, Resource | Placeholder image. Optional. | -| errorholderSrc | PixelMap, Resource | Error image. Optional. | -| objectFit | ImageFit | How the main image is resized to fit its container. Optional. | -| placeholderObjectFit | ImageFit | How the placeholder image is resized to fit its container. Optional. | -| errorholderObjectFit | ImageFit | How the error image is resized to fit its container. Optional. | -| writeCacheStrategy | CacheStrategyType | Cache writing strategy. Optional. | -| onlyRetrieveFromCache | boolean | Whether to skip network and local requests. Optional.| -| customGetImage | (context: Context, src: string | Custom image download. Optional. | -| border | BorderOptions | Border corner. Optional. | -| priority | taskpool.Priority | Load priority. Optional. | -| context | common.UIAbilityContext | Context. Optional. | -| progressListener | (progress: number)=>void | Progress. Optional. | -| signature | String | Custom cache signature. Optional. | -| headerOption | Array\ | Request headers. Optional. | -| transformation | PixelMapTransformation | Image transformation. Optional. | -| drawingColorFilter | ColorFilter | Drawing color filter. Optional. | -| onComplete | (event:EventImage \| undefined)=>void | Callback for image loading completion. Optional. | -| onLoadListener | onLoadStart:()=>void,onLoadSuccess:(data:string\|Pixelmap)=>void | Callback for image loading events. Optional. | +| 参数名称 | 入参内容 | 功能简介 | +|-----------------------|-------------------------------------------------------|-----------------| +| loadSrc | string、PixelMap、Resource | 主图展示 | +| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) | +| errorholderSrc | PixelMap、Resource | 错误图展示(可选) | +| objectFit | ImageFit | 主图填充效果(可选) | +| placeholderObjectFit | ImageFit | 占位图填充效果(可选) | +| errorholderObjectFit | ImageFit | 错误图填充效果(可选) | +| writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) | +| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) | +| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 | +| border | BorderOptions | 边框圆角(可选) | +| priority | taskpool.Priority | 加载优先级(可选) | +| context | common.UIAbilityContext | 上下文(可选) | +| progressListener | (progress: number)=>void | 进度(可选) | +| signature | String | 自定义缓存关键字(可选) | +| headerOption | Array | 设置请求头(可选) | +| transformation | PixelMapTransformation | 图片变换(可选) | +| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) | +| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) | +| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 | -### ImageKnife +### ImageKnife接口 -| Parameter | Type | Description | -| ----------------- | ------------------------------------------------------------ | -------------------------- | -| initMemoryCache | newMemoryCache: IMemoryCache | Initializes a custom memory cache strategy. | -| initFileCache | context: Context, size: number, memory: number | Initializes the file cache size and quantity | -| preLoadCache | loadSrc: string I ImageKnifeOption | Preloads and returns the file cache path. | -| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | Obtains resources from memory or file cache.| -| addHeader | key: string, value: Object | Adds a global HTTP request header. | -| setHeaderOptions | Array | Sets global HTTP request headers. | -| deleteHeader | key: string | Deletes a global HTTP request header. | -| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | -| setEngineKeyImpl | IEngineKey | Sets a global cache key generation strategy. | -| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | Writes to the memory disk cache. | -| removeMemoryCache | url: string | Removes an entry from the memory cache. | -| removeFileCache | url: string | Removes an entry from the file cache. | -### Graphics tRansformation Types (GPUImage Dependency Required) +| 参数名称 | 入参内容 | 功能简介 | +|------------------|-------------------------------------------------------------------------------------------------------|---------------| +| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 | +| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 | +| preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 | +| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 | +| addHeader | key: string, value: Object | 全局添加http请求头 | +| setHeaderOptions | Array | 全局设置http请求头 | +| deleteHeader | key: string | 全局删除http请求头 | +| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise | 全局设置自定义下载 | +| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 | +| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 | +| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 | +| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 | +### 图形变换类型(需要为GPUImage添加依赖项) -| Type | Description | -| ------------------------ | ----------------------------- | -| BlurTransformation | Blurs the image. | -| BrightnessTransformation | Applies a brightness filter. | -| CropSquareTransformation | Crops the image to a square. | -| CropTransformation | Crops the image to a custom rectangle. | -| GrayScaleTransformation | Applies a grayscale filter. | -| InvertTransformation | Applies an inversion filter. | -| KuwaharaTransformation | Applies a Kuwahara filter (requires **GPUImage**). | -| MaskTransformation | Applies a mask. | -| PixelationTransformation | Applies a pixelation filter (requires **GPUImage**).| -| SepiaTransformation | Applies a sepia filter (requires **GPUImage**).| -| SketchTransformation | Applies a sketch filter (requires **GPUIImage**). | -| SwirlTransformation | Applies a swirl filter (requires **GPUImage**). | -| ToonTransformation | Applies a cartoon filter (requires **GPUImage**). | -| VignetterTransformation | Applies a vignette filter (requires **GPUImage**). | +| 类型 | 相关描述 | +| ---------------------------------- | ----------------------------- | +| BlurTransformation | 模糊处理 | +| BrightnessTransformation | 亮度滤波器 | +| CropSquareTransformation | 正方形剪裁 | +| CropTransformation | 自定义矩形剪裁 | +| GrayScaleTransformation | 灰度级滤波器 | +| InvertTransformation | 反转滤波器 | +| KuwaharaTransformation | 桑原滤波器(使用GPUIImage) | +| MaskTransformation | 遮罩 | +| PixelationTransformation | 像素化滤波器(使用GPUIImage) | +| SepiaTransformation | 乌墨色滤波器(使用GPUIImage) | +| SketchTransformation | 素描滤波器(使用GPUIImage) | +| SwirlTransformation | 扭曲滤波器(使用GPUIImage) | +| ToonTransformation | 动画滤波器(使用GPUIImage) | +| VignetterTransformation | 装饰滤波器(使用GPUIImage) | -## Downloading and Installing the GPUImage Dependency -Method 1: In the **Terminal** window, run the following command to install the third-party HAR. DevEco Studio will automatically add the HAR as a dependency to the **oh-package.json5** file of the project. +## 下载安装GPUImage依赖 +方法一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。 ``` ohpm install @ohos/gpu_transform ``` -Method 2: Set the third-party HAR as a dependency in the **oh-package.json5** file of the project. The following is a configuration example: +方法二: 在工程的oh-package.json5中设置三方包依赖,配置示例如下: ``` "dependencies": { "@ohos/gpu_transform": "^1.0.2" } ``` -## Constraints +## 约束与限制 -This project has been verified in the following version: +在下述版本验证通过: +DevEco Studio 5.0 Canary3(5.0.3.221)--SDK:API12 -DevEco Studio: 5.0 Canary3 (5.0.3.502), SDK: API 12 (5.0.0.31) +## 贡献代码 -## How to Contribute +使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) +给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) 。 -If you find any problem during the use, submit an [Issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) or a [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) to us. +## 开源协议 -## License +本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。 -This project is licensed under [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE). +## 遗留问题 -## Known Issues - -- The **ImageFit** attribute cannot be set for the **ImageKnifeAnimator** component. -- The **border** attribute of the **ImageKnifeAnimator** component cannot make the image rounded corners. +- ImageKnifeAnimator组件无法设置ImageFit属性 +- ImageKnifeAnimator组件设置border属性无法将图片变为圆角 \ No newline at end of file diff --git a/entry/src/main/ets/pages/ImageAnimatorPage.ets b/entry/src/main/ets/pages/ImageAnimatorPage.ets index 5837f7f..9269280 100644 --- a/entry/src/main/ets/pages/ImageAnimatorPage.ets +++ b/entry/src/main/ets/pages/ImageAnimatorPage.ets @@ -12,82 +12,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AnimatorOption, ImageKnifeAnimatorComponent,ImageKnifeOption } from "@ohos/libraryimageknife" +import { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimageknife" @Entry -@ComponentV2 +@Component struct ImageAnimatorPage { - @Local animatorOption: AnimatorOption = new AnimatorOption({ + @State animatorOption: AnimatorOption = { state: AnimationStatus.Running, - iterations: -1, - onFinish:()=>{ - console.log("ImageKnifeAnimatorComponent animatorOption onFinish") - }, - onStart:()=>{ - console.log("ImageKnifeAnimatorComponent animatorOption onStart") - }, - onPause:()=>{ - console.log("ImageKnifeAnimatorComponent animatorOption onPause") - }, - onCancel:()=>{ - console.log("ImageKnifeAnimatorComponent animatorOption onCancel") - }, - onRepeat:()=>{ - console.log("ImageKnifeAnimatorComponent animatorOption onRepeat") - } - }) - @Local animatorOption1: AnimatorOption = new AnimatorOption({ - state: AnimationStatus.Initial - }) - @Local animatorOption2: AnimatorOption = new AnimatorOption({ - state: AnimationStatus.Initial, - reverse: true - }) + iterations: -1 + } build() { Column(){ Flex(){ - Button($r('app.string.Play')).onClick(()=>{ + Button("播放").onClick(()=>{ this.animatorOption.state = AnimationStatus.Running }) - Button($r('app.string.Pause')).onClick(()=>{ + Button("暂停").onClick(()=>{ this.animatorOption.state = AnimationStatus.Paused }) - Button($r('app.string.Stop')).onClick(()=>{ + Button("停止").onClick(()=>{ this.animatorOption.state = AnimationStatus.Stopped }) - Button($r('app.string.Infinite_loop')).onClick(()=>{ + Button("无限循环").onClick(()=>{ this.animatorOption.iterations = -1 }) - Button($r('app.string.Play_once')).onClick(()=>{ + Button("播放一次").onClick(()=>{ this.animatorOption.iterations = 1 }) - Button($r('app.string.Play_twice')).onClick(()=>{ + Button("播放两次").onClick(()=>{ this.animatorOption.iterations = 2 }) } ImageKnifeAnimatorComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }),animatorOption:this.animatorOption - }).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) - Text($r('app.string.Display_the_first_frame')).fontSize(20) - ImageKnifeAnimatorComponent({ - imageKnifeOption:new ImageKnifeOption({ - loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", - placeholderSrc:$r('app.media.loading'), - errorholderSrc:$r('app.media.failed') - }),animatorOption:this.animatorOption1 - }).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) - Text($r('app.string.Display_the_last_frame')).fontSize(20) - ImageKnifeAnimatorComponent({ - imageKnifeOption:new ImageKnifeOption({ - loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", - placeholderSrc:$r('app.media.loading'), - errorholderSrc:$r('app.media.failed') - }),animatorOption:this.animatorOption2 - }).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) + },animatorOption:this.animatorOption + }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30}) }.width("100%").height("100%") } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/ImageTransformation.ets b/entry/src/main/ets/pages/ImageTransformation.ets index 5a88f34..5e4e007 100644 --- a/entry/src/main/ets/pages/ImageTransformation.ets +++ b/entry/src/main/ets/pages/ImageTransformation.ets @@ -35,17 +35,17 @@ import { import { collections } from '@kit.ArkTS' @Entry -@ComponentV2 +@Component struct ImageTransformation { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.pngSample'), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Contain - }) - @Local isRound: boolean = false; - @Local isContrast: boolean = false; - @Local isRotate: boolean = false; + } + @State isRound: boolean = false; + @State isContrast: boolean = false; + @State isRotate: boolean = false; isBlur: boolean = false isBrightness: boolean = false isGrayScale: boolean = false; @@ -412,14 +412,14 @@ struct ImageTransformation { if (this.isMask) { transformations.push(new MaskTransformation($r('app.media.mask_starfish'))); } - this.imageKnifeOption = new ImageKnifeOption({ + this.imageKnifeOption = { loadSrc: $r('app.media.pngSample'), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Contain, border: { radius: this.isRound ? { topLeft: 50, bottomRight: 50 } : 0 }, transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined - }) + } if (this.isCropCircle) { this.imageKnifeOption.objectFit = ImageFit.Cover; this.imageKnifeOption.border = { radius: 150 }; diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index a5bf801..329e33a 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -15,7 +15,7 @@ import router from '@system.router'; @Entry -@ComponentV2 +@Component struct Index { getResourceString(res:Resource){ diff --git a/entry/src/main/ets/pages/ListPage.ets b/entry/src/main/ets/pages/ListPage.ets index 1c6d614..c604d97 100644 --- a/entry/src/main/ets/pages/ListPage.ets +++ b/entry/src/main/ets/pages/ListPage.ets @@ -15,11 +15,11 @@ import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'; @Entry -@ComponentV2 +@Component struct ListPage { private data: string[] = [] - @Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ loadSrc: $r('app.media.startIcon')}) + @State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon')} aboutToAppear(): void { diff --git a/entry/src/main/ets/pages/LoadStatePage.ets b/entry/src/main/ets/pages/LoadStatePage.ets index 2c0c4d8..80c41a3 100644 --- a/entry/src/main/ets/pages/LoadStatePage.ets +++ b/entry/src/main/ets/pages/LoadStatePage.ets @@ -16,12 +16,12 @@ import { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife" import matrix4 from '@ohos.matrix4' @Entry -@ComponentV2 +@Component struct LoadStatePage { starTime:number = new Date().getTime() - @Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r("app.media.rabbit"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), @@ -35,22 +35,22 @@ struct LoadStatePage { }, }, border: { radius: 50 } - }) - @Local imageKnifeOption1: ImageKnifeOption = new ImageKnifeOption({ + } + @State imageKnifeOption1: ImageKnifeOption = { loadSrc: $r('app.media.startIcon') - }) - @Local message: string = "" - @Local currentWidth: number = 200 - @Local currentHeight: number = 200 - @Local typeValue: string = "" + } + @State message: string = "" + @State currentWidth: number = 200 + @State currentHeight: number = 200 + @State typeValue: string = "" build() { Column() { - Text($r('app.string.TIPS')) + Text('测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存') .margin({ top: 20 }) Row() { - Button($r('app.string.Test_failure_success')) + Button('测试失败/成功场景') .onClick(() => { - this.ImageKnifeOption = new ImageKnifeOption({ + this.ImageKnifeOption = { loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), @@ -75,15 +75,15 @@ struct LoadStatePage { onComplete:(event)=>{ console.error("Load onComplete width:"+event?.width , " height:"+event?.height , " componentWidth:"+event?.componentWidth," componentHeight:" + event?.componentHeight); } - }) + } }) } .margin({ top: 20 }) Text(this.typeValue) ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(this.currentHeight).width(this.currentWidth) .margin({ top: 20 }) - Button($r('app.string.Custom_download_failed')).onClick(()=>{ - this.imageKnifeOption1 = new ImageKnifeOption({ + Button("自定义下载失败").onClick(()=>{ + this.imageKnifeOption1 = { loadSrc: "abc", placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed'), @@ -93,7 +93,7 @@ struct LoadStatePage { this.message = "err:" + err } } - }) + } }).margin({ top: 20 }) Text(this.message).fontSize(20).margin({ top: 20 }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).height(this.currentHeight).width(this.currentWidth) diff --git a/entry/src/main/ets/pages/LongImagePage.ets b/entry/src/main/ets/pages/LongImagePage.ets index 0d09a96..c8f6e1f 100644 --- a/entry/src/main/ets/pages/LongImagePage.ets +++ b/entry/src/main/ets/pages/LongImagePage.ets @@ -12,10 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' +import { ImageKnifeComponent } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct LongImagePage { build() { @@ -25,13 +25,13 @@ struct LongImagePage { // Image($r("app.media.aaa")).objectFit(ImageFit.Auto).width(200) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc:"https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg", //src:$r("app.media.aaa"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Auto - }) + } }) } .height('100%') .width('100%') diff --git a/entry/src/main/ets/pages/ManyPhotoShowPage.ets b/entry/src/main/ets/pages/ManyPhotoShowPage.ets index 3c9edf3..0719141 100644 --- a/entry/src/main/ets/pages/ManyPhotoShowPage.ets +++ b/entry/src/main/ets/pages/ManyPhotoShowPage.ets @@ -12,12 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BlurTransformation, ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife'; +import { ImageKnifeComponent } from '@ohos/libraryimageknife'; @Entry -@ComponentV2 +@Component struct ManyPhotoShowPage { private data: TestDataSource = new TestDataSource(); @@ -36,16 +36,15 @@ struct ManyPhotoShowPage { // loadSrc: item.thumbnail, // mainScaleType: ScaleType.FIT_XY, // } }) - ImageKnifeComponent({imageKnifeOption:new ImageKnifeOption({ + ImageKnifeComponent({imageKnifeOption:{ loadSrc: item.thumbnail, //src:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", // src: this.localFile, placeholderSrc:$r("app.media.loading"), errorholderSrc:$r("app.media.failed"), objectFit: ImageFit.Auto, - border: {radius:50}, - transformation:new BlurTransformation(5) - })}) + border: {radius:50} + }}) } .width(56).height(56) //滤镜标题 diff --git a/entry/src/main/ets/pages/ObjectFitPage.ets b/entry/src/main/ets/pages/ObjectFitPage.ets index 58ca101..c86415f 100644 --- a/entry/src/main/ets/pages/ObjectFitPage.ets +++ b/entry/src/main/ets/pages/ObjectFitPage.ets @@ -15,49 +15,49 @@ import { ImageKnife, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct ObjectFitPage { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r("app.media.app_icon"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Fill - }) + } build() { Column() { - Button($r('app.string.Main_image_Fill')).onClick(()=>{ - this.imageKnifeOption = new ImageKnifeOption({ + Button("主图Fill拉伸填充").onClick(()=>{ + this.imageKnifeOption = { loadSrc: $r("app.media.app_icon"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Fill - }) + } }) - Button($r('app.string.Maintain_proportion_filling')).margin({top:10}).onClick(async () => { + Button("占位图Contain保持比例填充").margin({top:10}).onClick(async () => { ImageKnife.getInstance().removeAllMemoryCache() await ImageKnife.getInstance().removeAllFileCache() - this.imageKnifeOption = new ImageKnifeOption({ + this.imageKnifeOption = { loadSrc: "https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg", placeholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Fill, placeholderObjectFit: ImageFit.Contain - }) + } }) - Button($r('app.string.Error_graph_None')).margin({top:10}).onClick(() => { - this.imageKnifeOption = new ImageKnifeOption({ + Button("错误图None不变化").margin({top:10}).onClick(() => { + this.imageKnifeOption = { loadSrc: "http://xxxxx", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Fill, errorholderObjectFit: ImageFit.None - }) + } }) ImageKnifeComponent({ diff --git a/entry/src/main/ets/pages/SignatureTestPage.ets b/entry/src/main/ets/pages/SignatureTestPage.ets index 8fc1763..5d60c3a 100644 --- a/entry/src/main/ets/pages/SignatureTestPage.ets +++ b/entry/src/main/ets/pages/SignatureTestPage.ets @@ -16,18 +16,18 @@ import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'; @Entry -@ComponentV2 +@Component struct SignatureTestPage { - @Local imageKnifeOption1: ImageKnifeOption =new ImageKnifeOption( + @State imageKnifeOption1: ImageKnifeOption = { loadSrc: $r('app.media.icon'), placeholderSrc:$r("app.media.loading"), - }); - @Local imageKnifeOption2: ImageKnifeOption =new ImageKnifeOption( + }; + @State imageKnifeOption2: ImageKnifeOption = { loadSrc: $r('app.media.icon'), placeholderSrc:$r("app.media.loading"), - }); + }; build() { Scroll() { @@ -37,11 +37,11 @@ struct SignatureTestPage { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Button($r('app.string.Load')) .onClick(() => { - this.imageKnifeOption1 = new ImageKnifeOption({ + this.imageKnifeOption1 = { loadSrc: 'https://img-blog.csdn.net/20140514114029140', placeholderSrc:$r("app.media.loading"), signature: "1" - }) + } }).margin({ top: 5, left: 3 }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) }.width('100%').backgroundColor(Color.Pink) @@ -50,11 +50,11 @@ struct SignatureTestPage { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Button($r('app.string.Load')) .onClick(() => { - this.imageKnifeOption2 = new ImageKnifeOption({ + this.imageKnifeOption2 = { loadSrc: 'https://img-blog.csdn.net/20140514114029140', placeholderSrc:$r("app.media.loading"), signature: new Date().getTime().toString() - }) + } }).margin({ top: 5, left: 3 }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300) }.width('100%').backgroundColor(Color.Pink) diff --git a/entry/src/main/ets/pages/SingleImage.ets b/entry/src/main/ets/pages/SingleImage.ets index 3671c6c..079c8e4 100644 --- a/entry/src/main/ets/pages/SingleImage.ets +++ b/entry/src/main/ets/pages/SingleImage.ets @@ -12,19 +12,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent,BlurTransformation,ImageKnifeOption } from '@ohos/libraryimageknife'; +import { ImageKnifeComponent,BlurTransformation } from '@ohos/libraryimageknife'; import fs from '@ohos.file.fs'; import image from '@ohos.multimedia.image'; import { common2D, drawing } from '@kit.ArkGraphics2D'; @Entry -@ComponentV2 +@Component struct SingleImage { resource: string = "app.media.svgSample" scroller: Scroller = new Scroller; localFile: string = getContext(this).filesDir + "/icon.png" - @Local pixelMap:PixelMap | undefined = undefined; - @Local DrawingColorFilter: ColorFilter | undefined = undefined + @State pixelMap:PixelMap | undefined = undefined; + @State DrawingColorFilter: ColorFilter | undefined = undefined private color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 }; aboutToAppear(): void { // 拷贝本地文件 @@ -46,12 +46,12 @@ struct SingleImage { .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: $r("app.media.svgSample"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain - }) + } }).width(100).height(100) .onClick(()=>{ this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN); @@ -60,48 +60,48 @@ struct SingleImage { .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: this.localFile, placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain - }) + } }).width(100).height(100) Text($r('app.string.Network_images')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain, progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)} - }) + } }).width(100).height(100) Text($r('app.string.Custom_network_download')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain, customGetImage: custom, transformation: new BlurTransformation(10) - }) + } }).width(100).height(100) Text($r('app.string.PixelMap_loads_images')) .fontSize(30) .fontWeight(FontWeight.Bold) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: this.pixelMap!, placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain, - }) + } }).width(100).height(100) } .width('100%') diff --git a/entry/src/main/ets/pages/TestCommonImage.ets b/entry/src/main/ets/pages/TestCommonImage.ets index 66f3514..669220c 100644 --- a/entry/src/main/ets/pages/TestCommonImage.ets +++ b/entry/src/main/ets/pages/TestCommonImage.ets @@ -12,10 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent ,ImageKnifeOption} from '@ohos/libraryimageknife'; +import { ImageKnifeComponent } from '@ohos/libraryimageknife'; @Entry -@ComponentV2 +@Component struct TestCommonImage { private data: Array = [] aboutToAppear(): void { @@ -30,13 +30,13 @@ struct TestCommonImage { FlowItem() { Column(){ ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: item, placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.failed"), objectFit: ImageFit.Contain, signature: "aaa" - }) + } }).width("50%").height(200) } }.height(200) diff --git a/entry/src/main/ets/pages/TestErrorHolderPage.ets b/entry/src/main/ets/pages/TestErrorHolderPage.ets index 0b716e2..f49ab6c 100644 --- a/entry/src/main/ets/pages/TestErrorHolderPage.ets +++ b/entry/src/main/ets/pages/TestErrorHolderPage.ets @@ -12,34 +12,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' +import { ImageKnifeComponent } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestErrorHolderPage { build() { Column() { Text("ImageKnifeComponent1").fontSize(20) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: "abc", errorholderSrc:$r('app.media.failed') - }) + } }).width(200).height(200) Text("ImageKnifeComponent2").fontSize(20) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: "abc", errorholderSrc:$r('app.media.startIcon') - }) + } }).width(200).height(200) Text("ImageKnifeComponent2").fontSize(20) ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: "abc", errorholderSrc:$r('app.media.mask_starfish') - }) + } }).width(200).height(200) } .height('100%') .width('100%') diff --git a/entry/src/main/ets/pages/TestHeader.ets b/entry/src/main/ets/pages/TestHeader.ets index 50027b0..9be198e 100644 --- a/entry/src/main/ets/pages/TestHeader.ets +++ b/entry/src/main/ets/pages/TestHeader.ets @@ -15,9 +15,9 @@ import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestPrefetchToFileCachePage { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", placeholderSrc:$r('app.media.loading'), headerOption:[ @@ -26,7 +26,7 @@ struct TestPrefetchToFileCachePage { value:"单个" } ] - }) + } build() { Column() { diff --git a/entry/src/main/ets/pages/TestHspPreLoadImage.ets b/entry/src/main/ets/pages/TestHspPreLoadImage.ets index e1084b8..16ff464 100644 --- a/entry/src/main/ets/pages/TestHspPreLoadImage.ets +++ b/entry/src/main/ets/pages/TestHspPreLoadImage.ets @@ -15,7 +15,7 @@ import { IndexComponent } from "@ohos/libraryimageknife" @Entry -@ComponentV2 +@Component struct TestHspPreLoadImage { build() { Column() { diff --git a/entry/src/main/ets/pages/TestImageFlash.ets b/entry/src/main/ets/pages/TestImageFlash.ets index df2d363..53b9826 100644 --- a/entry/src/main/ets/pages/TestImageFlash.ets +++ b/entry/src/main/ets/pages/TestImageFlash.ets @@ -12,9 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' +import { ImageKnifeComponent } from '@ohos/libraryimageknife' -@ObservedV2 +@Observed export class MsgModel { id: string cId: string @@ -30,10 +30,10 @@ export class MsgModel { } -// @Reusable -@ComponentV2 +@Reusable +@Component export struct MsgItem { - @Param count: number = 0 + count: number = 0 private data: Array = [ "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg", "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg", @@ -59,37 +59,37 @@ export struct MsgItem { build(){ if (this.count % 2 == 0 && this.count <6){ ImageKnifeComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:$r("app.media.startIcon"), placeholderSrc:$r("app.media.loading") - }),syncLoad:true + },syncLoad:true }) }else if (this.count > 6 && this.count - 6 < this.data.length){ ImageKnifeComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:this.data[this.count - 6], placeholderSrc:$r("app.media.loading") - }),syncLoad:true + },syncLoad:true }) }else { ImageKnifeComponent({ - imageKnifeOption:new ImageKnifeOption({ + imageKnifeOption:{ loadSrc:$r("app.media.pngSample"), placeholderSrc:$r("app.media.loading") - }),syncLoad:true + },syncLoad:true }) } } } @Entry -@ComponentV2 +@Component struct ImageTestPage { count : number = 0 rCount: number = 0 scroller: Scroller = new Scroller() - @Local list: MsgModel[] = [] - @Local imageSize: number =100 + @State list: MsgModel[] = [] + @State imageSize: number =100 handAdd(){ this.count++ const msgItem = new MsgModel('add_id'+this.count, 'addBody'+this.count,'cId'+ this.count) diff --git a/entry/src/main/ets/pages/TestIsUrlExist.ets b/entry/src/main/ets/pages/TestIsUrlExist.ets index da91f54..ad4daa6 100644 --- a/entry/src/main/ets/pages/TestIsUrlExist.ets +++ b/entry/src/main/ets/pages/TestIsUrlExist.ets @@ -15,15 +15,15 @@ import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestIsUrlExist { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon'), placeholderSrc: $r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) - @Local source: PixelMap | string | Resource = $r("app.media.startIcon") - @Local source1: PixelMap | string | Resource = $r("app.media.startIcon") + } + @State source: PixelMap | string | Resource = $r("app.media.startIcon") + @State source1: PixelMap | string | Resource = $r("app.media.startIcon") build() { Column() { diff --git a/entry/src/main/ets/pages/TestPrefetchToFileCache.ets b/entry/src/main/ets/pages/TestPrefetchToFileCache.ets index c541bd1..a1a1787 100644 --- a/entry/src/main/ets/pages/TestPrefetchToFileCache.ets +++ b/entry/src/main/ets/pages/TestPrefetchToFileCache.ets @@ -15,19 +15,19 @@ import { ImageKnifeComponent,ImageKnife,ImageKnifeOption } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestPrefetchToFileCachePage { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc:$r('app.media.startIcon'), placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) + } async preload(url:string) { let fileCachePath = await ImageKnife.getInstance().preLoadCache(url) console.log("preload-fileCachePath=="+ fileCachePath) } async preload1(url:string) { - let fileCachePath = await ImageKnife.getInstance().preLoadCache(new ImageKnifeOption({ loadSrc: url })) + let fileCachePath = await ImageKnife.getInstance().preLoadCache({ loadSrc: url }) console.log("preload-fileCachePath1=="+ fileCachePath) } build() { diff --git a/entry/src/main/ets/pages/TestRemoveCache.ets b/entry/src/main/ets/pages/TestRemoveCache.ets index aadfc5a..8a25454 100644 --- a/entry/src/main/ets/pages/TestRemoveCache.ets +++ b/entry/src/main/ets/pages/TestRemoveCache.ets @@ -15,16 +15,16 @@ import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestRemoveCache { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon'), placeholderSrc: $r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) - @Local source: PixelMap | string | Resource = $r("app.media.startIcon"); - @Local source1: PixelMap | string | Resource = $r("app.media.startIcon"); - @Local url: string = ''; + } + @State source: PixelMap | string | Resource = $r("app.media.startIcon"); + @State source1: PixelMap | string | Resource = $r("app.media.startIcon"); + @State url: string = ''; build() { Column() { diff --git a/entry/src/main/ets/pages/TestSetCustomImagePage.ets b/entry/src/main/ets/pages/TestSetCustomImagePage.ets index 58a5c7b..809769f 100644 --- a/entry/src/main/ets/pages/TestSetCustomImagePage.ets +++ b/entry/src/main/ets/pages/TestSetCustomImagePage.ets @@ -15,17 +15,12 @@ import { ImageKnifeComponent, ImageKnife, ImageKnifeOption } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestSetCustomImagePage { - - getResourceString(res:Resource){ - return getContext().resourceManager.getStringSync(res.id) - } - - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon'), placeholderSrc: $r('app.media.loading') - }) + } aboutToAppear(): void { ImageKnife.getInstance().setCustomGetImage(custom) } @@ -34,23 +29,23 @@ struct TestSetCustomImagePage { } build() { Column() { - Button(this.getResourceString($r('app.string.Custom_network_download')) + " a").onClick(()=>{ - this.imageKnifeOption = new ImageKnifeOption({ + Button("自定义下载a").onClick(()=>{ + this.imageKnifeOption = { loadSrc: "aaa", placeholderSrc: $r('app.media.loading') - }) + } }) - Button(this.getResourceString($r('app.string.Custom_network_download')) + " b").onClick(()=>{ - this.imageKnifeOption = new ImageKnifeOption({ + Button("自定义下载b").onClick(()=>{ + this.imageKnifeOption = { loadSrc: "bbb", placeholderSrc: $r('app.media.loading') - }) + } }) - Button(this.getResourceString($r('app.string.Custom_network_download')) + " c").onClick(()=>{ - this.imageKnifeOption = new ImageKnifeOption({ + Button("自定义下载c").onClick(()=>{ + this.imageKnifeOption = { loadSrc: "ccc", placeholderSrc: $r('app.media.loading') - }) + } }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption diff --git a/entry/src/main/ets/pages/TestTaskResourcePage.ets b/entry/src/main/ets/pages/TestTaskResourcePage.ets index 0578bca..125d85e 100644 --- a/entry/src/main/ets/pages/TestTaskResourcePage.ets +++ b/entry/src/main/ets/pages/TestTaskResourcePage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife" +import { ImageKnifeComponent } from "@ohos/libraryimageknife" @ComponentV2 export struct ZuImage { @@ -24,12 +24,12 @@ export struct ZuImage { if (this.src) { //当前版本存在bug ImageKnifeComponent({ - imageKnifeOption: new ImageKnifeOption({ + imageKnifeOption: { loadSrc: this.src, placeholderSrc: this.placeholderSrc, errorholderSrc: this.errorholderSrc ?? this.placeholderSrc, objectFit: ImageFit.Cover - }) + } }) } else { Image(this.placeholderSrc) diff --git a/entry/src/main/ets/pages/TestWriteCacheStage.ets b/entry/src/main/ets/pages/TestWriteCacheStage.ets index a5f0431..6b0b203 100644 --- a/entry/src/main/ets/pages/TestWriteCacheStage.ets +++ b/entry/src/main/ets/pages/TestWriteCacheStage.ets @@ -15,55 +15,55 @@ import { ImageKnifeComponent,CacheStrategy,ImageKnifeOption } from '@ohos/libraryimageknife' @Entry -@ComponentV2 +@Component struct TestWriteCacheStage { - @Local imageKnifeOption1: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption1: ImageKnifeOption = { loadSrc:$r('app.media.startIcon'), placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) - @Local imageKnifeOption2: ImageKnifeOption = new ImageKnifeOption({ + } + @State imageKnifeOption2: ImageKnifeOption = { loadSrc:$r('app.media.startIcon'), placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) - @Local imageKnifeOption3: ImageKnifeOption = new ImageKnifeOption({ + } + @State imageKnifeOption3: ImageKnifeOption = { loadSrc:$r('app.media.startIcon'), placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed') - }) + } build() { Column() { - Button($r('app.string.Write_memory_and_file')).margin({top:10}).onClick(async ()=>{ - this.imageKnifeOption1 = new ImageKnifeOption({ + Button("写入内存文件缓存").margin({top:10}).onClick(async ()=>{ + this.imageKnifeOption1 = { loadSrc:'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed'), writeCacheStrategy:CacheStrategy.Default - }) + } }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(200).height(200).margin({top:10}) - Button($r('app.string.Write_memory')).margin({top:10}).onClick(async ()=>{ - this.imageKnifeOption2 = new ImageKnifeOption({ + Button("写入内存缓存").margin({top:10}).onClick(async ()=>{ + this.imageKnifeOption2 = { loadSrc:"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed'), writeCacheStrategy:CacheStrategy.Memory - }) + } }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(200).height(200).margin({top:10}) - Button($r('app.string.Write_file')).margin({top:10}).onClick(async ()=>{ - this.imageKnifeOption3 = new ImageKnifeOption({ + Button("写入文件缓存").margin({top:10}).onClick(async ()=>{ + this.imageKnifeOption3 = { loadSrc:'https://img-blog.csdn.net/20140514114029140', placeholderSrc:$r('app.media.loading'), errorholderSrc:$r('app.media.failed'), writeCacheStrategy:CacheStrategy.File - }) + } }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption3 diff --git a/entry/src/main/ets/pages/TransformPage.ets b/entry/src/main/ets/pages/TransformPage.ets index 0288c1d..29fbfd5 100644 --- a/entry/src/main/ets/pages/TransformPage.ets +++ b/entry/src/main/ets/pages/TransformPage.ets @@ -17,17 +17,17 @@ import matrix4 from '@ohos.matrix4' @Entry -@ComponentV2 +@Component struct TransformPage { private custom_scale:number = 1 - @Local matrix1:object = matrix4.identity().scale({ x: 1, y: 1 }) - @Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State matrix1:object = matrix4.identity().scale({ x: 1, y: 1 }) + @State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r("app.media.rabbit"), placeholderSrc: $r("app.media.loading"), errorholderSrc: $r("app.media.app_icon"), objectFit: ImageFit.Contain, border: { radius: 50 } - }) + } build() { Column() { diff --git a/entry/src/main/ets/pages/User.ets b/entry/src/main/ets/pages/User.ets index 603b767..1e3e582 100644 --- a/entry/src/main/ets/pages/User.ets +++ b/entry/src/main/ets/pages/User.ets @@ -15,50 +15,24 @@ import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife' // const logger = new imUtils.logger.IMLogger('Avatar') -@ObservedV2 -export class MyStorage { - static instance:MyStorage | undefined = undefined - static getInstance(){ - if(MyStorage.instance == undefined) { - MyStorage.instance = new MyStorage() - } - return MyStorage.instance - } - @Trace WeLink_Mob_fontSize_multiple: number = 1 + +class MyImageOption extends ImageKnifeOption { + account?: string } -@ComponentV2 +@Component export struct UserAvatar { + @Prop @Watch('userInfoUpdate') userInfo: string = "" // @Prop userInfo: string = "" imgSize: number = 100 radius: number = 12 borderSize: number = 0 imgSizes: number = 1 - @Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption() + @State ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption() + @StorageProp('WeLink_Mob_fontSize_multiple') @Watch('updateImgSize') WeLink_Mob_fontSize_multiple: number = 0 scalable: boolean = true; - @Local calcImgSize: number = 100 - @Param userInfo: string = "" - @Monitor('userInfo') - userInfoUpdate() { - // if (uri === 'userInfo' && this.imageKnifeOption.account !== this.userInfo.contactId) return; - // // logger.info(`userInfoUpdate uri=${uri} oldAcc=${this.imageKnifeOption.loadSrc} nowAcc=${this.userInfo.externalHeadUrl}`) - // if (this.userInfo.externalHeadUrl === this.imageKnifeOption.loadSrc && this.userInfo.infoUpdateTime.getTime() - // .toString() === this.imageKnifeOption?.signature?.getKey()) return; - this.ImageKnifeOption = new ImageKnifeOption({ - //TODO:写死loadSRC,场景:变更组件大小,所有图片不显示 - loadSrc: this.userInfo, - placeholderSrc: $r('app.media.loading'), - errorholderSrc: $r('app.media.failed'), - border: { radius:20,width:5,color:$r('app.color.start_window_background') }, - objectFit:ImageFit.Contain - // signature: new ObjectKey(this.userInfo.infoUpdateTime.getTime().toString()) - }) - } - @Local storage: MyStorage = MyStorage.getInstance() - @Monitor('storage.WeLink_Mob_fontSize_multiple') - updateImgSize() { - this.setImageSize() - } + @State calcImgSize: number = 100 + aboutToAppear(): void { this.userInfoUpdate() this.setImageSize() @@ -67,19 +41,39 @@ export struct UserAvatar { setImageSize() { if (!this.scalable) { this.calcImgSize = this.imgSize - } else if (this.storage.WeLink_Mob_fontSize_multiple < 0.9) { + } else if (this.WeLink_Mob_fontSize_multiple < 0.9) { this.calcImgSize = this.imgSize * 0.9 - } else if (this.storage.WeLink_Mob_fontSize_multiple > 1.6) { + } else if (this.WeLink_Mob_fontSize_multiple > 1.6) { this.calcImgSize = this.imgSize * 1.6 } else { - this.calcImgSize = this.imgSize * this.storage.WeLink_Mob_fontSize_multiple + this.calcImgSize = this.imgSize * this.WeLink_Mob_fontSize_multiple } } + updateImgSize() { + this.setImageSize() + } + aboutToReuse(param: ESObject) { this.userInfoUpdate() } + userInfoUpdate() { + // if (uri === 'userInfo' && this.imageKnifeOption.account !== this.userInfo.contactId) return; + // // logger.info(`userInfoUpdate uri=${uri} oldAcc=${this.imageKnifeOption.loadSrc} nowAcc=${this.userInfo.externalHeadUrl}`) + // if (this.userInfo.externalHeadUrl === this.imageKnifeOption.loadSrc && this.userInfo.infoUpdateTime.getTime() + // .toString() === this.imageKnifeOption?.signature?.getKey()) return; + this.ImageKnifeOption = { + //TODO:写死loadSRC,场景:变更组件大小,所有图片不显示 + loadSrc: this.userInfo, + placeholderSrc: $r('app.media.loading'), + errorholderSrc: $r('app.media.failed'), + border: { radius:20,width:5,color:$r('app.color.start_window_background') }, + objectFit:ImageFit.Contain + // signature: new ObjectKey(this.userInfo.infoUpdateTime.getTime().toString()) + } + } + build() { Row() { // Image(this.imageKnifeOption.loadSrc) diff --git a/entry/src/main/ets/pages/UserPage.ets b/entry/src/main/ets/pages/UserPage.ets index 30e711d..ee210bc 100644 --- a/entry/src/main/ets/pages/UserPage.ets +++ b/entry/src/main/ets/pages/UserPage.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { MyStorage, UserAvatar } from './User' +import { UserAvatar } from './User' class CommonDataSource implements IDataSource { private dataArray: T[] = [] @@ -55,9 +55,9 @@ class CommonDataSource implements IDataSource { } } @Entry -@ComponentV2 +@Component struct Index { - @Local hotCommendList:CommonDataSource = new CommonDataSource([]) + @State hotCommendList:CommonDataSource = new CommonDataSource([]) private data:string[] = [ "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg", "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg", @@ -85,42 +85,26 @@ struct Index { 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', ] aboutToAppear(): void { - MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 1 + this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data) + AppStorage.set("WeLink_Mob_fontSize_multiple",1) } build() { Column() { Button("bigger").onClick(()=>{ - MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 1.6 + AppStorage.set("WeLink_Mob_fontSize_multiple",1.6) }) Button("small").onClick(()=>{ - MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 0.8 + AppStorage.set("WeLink_Mob_fontSize_multiple",0.8) }) List(){ - // LazyForEach(this.hotCommendList,(item:string)=>{ - // ListItem(){ - // ReuseImage({ - // userInfo:item - // }).width("100%").height("100%").backgroundColor(Color.Yellow) - // }.width(200).height(200).margin({bottom:5}) - // }) - Repeat(this.data) - .each((repeatItem)=>{ - ListItem(){ - ReuseImage({ - userInfo:repeatItem.item - }).width("100%").height("100%").backgroundColor(Color.Yellow) - }.width(200).height(200).margin({bottom:5}).key("reuse") - }) - .key(item => item+"reuse") - .virtualScroll() - .template("1",(repeatItem)=>{ - ListItem(){ - ReuseImage({ - userInfo:repeatItem.item - }).width("100%").height("100%").backgroundColor(Color.Yellow) - }.width(200).height(200).margin({bottom:5}).key("reuse") - }) + LazyForEach(this.hotCommendList,(item:string)=>{ + ListItem(){ + ReuseImage({ + userInfo:item + }).width("100%").height("100%").backgroundColor(Color.Yellow) + }.width(200).height(200).margin({bottom:5}) + }) } // .cachedCount(20) .width("100%") @@ -131,13 +115,13 @@ struct Index { } -// @Reusable -@ComponentV2 +@Reusable +@Component struct ReuseImage { - @Param userInfo:string = "" - // aboutToReuse(params: ESObject): void { - // this.userInfo = params.userInfo - // } + @State userInfo:string = "" + aboutToReuse(params: ESObject): void { + this.userInfo = params.userInfo + } build() { Column(){ diff --git a/entry/src/main/ets/pages/dataShareUriLoadPage.ets b/entry/src/main/ets/pages/dataShareUriLoadPage.ets index 7392044..b3915b7 100644 --- a/entry/src/main/ets/pages/dataShareUriLoadPage.ets +++ b/entry/src/main/ets/pages/dataShareUriLoadPage.ets @@ -18,15 +18,15 @@ import { photoAccessHelper } from '@kit.MediaLibraryKit'; @Entry -@ComponentV2 +@Component struct DataShareUriLoadPage { - @Local imageKnifeOption1: ImageKnifeOption = - new ImageKnifeOption({ + @State imageKnifeOption1: ImageKnifeOption = + { loadSrc: $r('app.media.icon'), placeholderSrc: $r('app.media.loading'), errorholderSrc: $r('app.media.failed') - }); + }; build() { @@ -43,10 +43,10 @@ struct DataShareUriLoadPage { let photoViewPicker = new photoAccessHelper.PhotoViewPicker(); let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoViewPicker.select(photoSelectOptions); uris = photoSelectResult.photoUris; - this.imageKnifeOption1 = new ImageKnifeOption({ + this.imageKnifeOption1 = { loadSrc: uris[0], placeholderSrc:$r('app.media.loading') - }) + } }).margin({ top: 5, left: 3 }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) }.width('100%').backgroundColor(Color.Pink) diff --git a/library/src/main/ets/ImageKnife.ets b/library/src/main/ets/ImageKnife.ets index 41eeb64..69a6271 100644 --- a/library/src/main/ets/ImageKnife.ets +++ b/library/src/main/ets/ImageKnife.ets @@ -191,10 +191,10 @@ export class ImageKnife { */ getCacheImage(loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string): Promise { - let option: ImageKnifeOption = new ImageKnifeOption({ + let option: ImageKnifeOption = { loadSrc: loadSrc, signature:signature - }) + } let engineKeyImpl: IEngineKey = this.getEngineKeyImpl(); return new Promise((resolve, reject) => { @@ -218,7 +218,7 @@ export class ImageKnife { */ putCacheImage(url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) { let memoryKey = this.getEngineKeyImpl() - .generateMemoryKey(url, ImageKnifeRequestSource.SRC, new ImageKnifeOption({ loadSrc: url, signature: signature })); + .generateMemoryKey(url, ImageKnifeRequestSource.SRC, { loadSrc: url, signature: signature }); let fileKey = this.getEngineKeyImpl().generateFileKey(url, signature); let imageKnifeData: ImageKnifeData = { source: pixelMap, imageWidth: 0, imageHeight: 0 }; switch (cacheType) { @@ -252,9 +252,9 @@ export class ImageKnife { if (url instanceof ImageKnifeOption) { imageKnifeOption = url; } else { - imageKnifeOption = new ImageKnifeOption({ + imageKnifeOption = { loadSrc: url - }); + }; } let key = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature); if (this.fileCache !== undefined) { diff --git a/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets b/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets index 93cdf84..81a0f85 100644 --- a/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets +++ b/library/src/main/ets/components/ImageKnifeAnimatorComponent.ets @@ -19,14 +19,15 @@ import { ImageKnife } from '../ImageKnife'; import { LogUtil } from '../utils/LogUtil'; import { ImageKnifeRequestSource } from '../model/ImageKnifeData'; -@ComponentV2 +@Component export struct ImageKnifeAnimatorComponent { - @Param animatorOption: AnimatorOption = new AnimatorOption(); - @Local pixelMap: PixelMap | string | undefined = undefined - @Local imageAnimator: Array | undefined = undefined - @Local adaptiveWidth: Length = '100%' - @Local adaptiveHeight: Length = '100%' - @Local objectFit: ImageFit = ImageFit.Contain + @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption; + @State animatorOption: AnimatorOption = new AnimatorOption(); + @State pixelMap: PixelMap | string | undefined = undefined + @State imageAnimator: Array | undefined = undefined + @State adaptiveWidth: Length = '100%' + @State adaptiveHeight: Length = '100%' + @State objectFit: ImageFit = ImageFit.Contain private request: ImageKnifeRequest | undefined private lastWidth: number = 0 private lastHeight: number = 0 @@ -34,17 +35,7 @@ export struct ImageKnifeAnimatorComponent { private currentHeight: number = 0 private componentVersion: number = 0 private currentContext: common.UIAbilityContext | undefined = undefined - @Param imageKnifeOption: ImageKnifeOption = new ImageKnifeOption(); - @Monitor('imageKnifeOption', - "imageKnifeOption.loadSrc","imageKnifeOption.signature","imageKnifeOption.transformation","imageKnifeOption.border","imageKnifeOption.objectFit") - watchImageKnifeOption() { - if (this.request !== undefined) { - this.request.requestState = ImageKnifeRequestState.DESTROY - } - this.request = undefined - this.componentVersion++ - ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) - } + aboutToAppear(): void { this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit } @@ -95,6 +86,15 @@ export struct ImageKnifeAnimatorComponent { .onRepeat(this.animatorOption.onRepeat) } + watchImageKnifeOption() { + if (this.request !== undefined) { + this.request.requestState = ImageKnifeRequestState.DESTROY + } + this.request = undefined + this.componentVersion++ + ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight),true) + } + getCurrentContext(): common.UIAbilityContext { if (this.currentContext == undefined) { this.currentContext = getContext(this) as common.UIAbilityContext diff --git a/library/src/main/ets/components/ImageKnifeComponent.ets b/library/src/main/ets/components/ImageKnifeComponent.ets index f96cecc..bc5af04 100644 --- a/library/src/main/ets/components/ImageKnifeComponent.ets +++ b/library/src/main/ets/components/ImageKnifeComponent.ets @@ -21,13 +21,14 @@ import { ImageKnifeData, ImageKnifeRequestSource } from '../model/ImageKnifeData import { IEngineKey } from '../key/IEngineKey'; import { DefaultEngineKey } from '../key/DefaultEngineKey'; -@ComponentV2 +@Component export struct ImageKnifeComponent { - @Local pixelMap: PixelMap | string | undefined = undefined - @Param syncLoad: boolean = false - @Local adaptiveWidth: Length = '100%' - @Local adaptiveHeight: Length = '100%' - @Local objectFit: ImageFit = ImageFit.Contain + @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption; + @State pixelMap: PixelMap | string | undefined = undefined + @State syncLoad: boolean = false + @State adaptiveWidth: Length = '100%' + @State adaptiveHeight: Length = '100%' + @State objectFit: ImageFit = ImageFit.Contain private request: ImageKnifeRequest | undefined private lastWidth: number = 0 private lastHeight: number = 0 @@ -35,65 +36,45 @@ export struct ImageKnifeComponent { private currentHeight: number = 0 private componentVersion: number = 0 private currentContext: common.UIAbilityContext | undefined = undefined - @Param imageKnifeOption: ImageKnifeOption = new ImageKnifeOption(); - - @Monitor('imageKnifeOption', - "imageKnifeOption.loadSrc","imageKnifeOption.signature","imageKnifeOption.transformation","imageKnifeOption.border","imageKnifeOption.objectFit") - watchImageKnifeOption() { - this.clearLastRequest() - this.componentVersion++ - this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit - LogUtil.log("watchImageKnifeOption execute request:width=" + this.currentWidth + " height= " + this.currentHeight - + " loadSrc = " + this.request?.imageKnifeOption.loadSrc - + " placeholderSrc = " + this.request?.imageKnifeOption.placeholderSrc - + " errorholderSrc = " + this.request?.imageKnifeOption.errorholderSrc) - ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) - } aboutToAppear(): void { - this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit - - if(this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题,建议使用同步方式在aboutToAppear时加载图片 + //闪动问题失效,注释相应代码后续修复 + if(this.syncLoad) { let engineKey: IEngineKey = new DefaultEngineKey(); let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance() .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) if (memoryCacheSrc !== undefined){ - LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) + LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) + //画主图 this.pixelMap = memoryCacheSrc.source; - }else{ - LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) - if (this.imageKnifeOption.placeholderSrc !== undefined){ - let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance() - .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption)) - if (memoryCachePlace !== undefined){ - LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) - this.pixelMap = memoryCachePlace.source; - }else{ - LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) - } + }else { + let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance() + .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption)) + if (memoryCachePlace !== undefined){ + LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) + //画主图 + this.pixelMap = memoryCachePlace.source; } } } + this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit } aboutToDisappear(): void { - this.clearLastRequest() - } - - aboutToRecycle() { - this.clearLastRequest() - } - - /** - * 对已DESTROY的组件不再发起请求 - */ - private clearLastRequest(){ if (this.request !== undefined) { this.request.requestState = ImageKnifeRequestState.DESTROY this.request = undefined } } + aboutToRecycle() { + if (this.request !== undefined) { + this.request.requestState = ImageKnifeRequestState.DESTROY + this.request = undefined + } + this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit + } + build() { Image(this.pixelMap) .colorFilter(this.imageKnifeOption.drawingColorFilter) @@ -109,19 +90,27 @@ export struct ImageKnifeComponent { this.currentHeight = newValue.height as number this.lastWidth = oldValue.width as number this.lastHeight = oldValue.height as number - - // 条件1: 宽高值均有效,值>0. 条件2:当前宽高与上一次宽高不同 - if (this.currentWidth > 0 && this.currentHeight > 0 && - (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth)) { - LogUtil.log("onSizeChange execute request:width=" + this.currentWidth + " height= " + this.currentHeight - + " loadSrc = " + this.request?.imageKnifeOption.loadSrc - + " placeholderSrc = " + this.request?.imageKnifeOption.placeholderSrc - + " errorholderSrc = " + this.request?.imageKnifeOption.errorholderSrc) - ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) + if (this.currentWidth <= 0 || this.currentHeight <= 0) { + // 存在宽或者高为0,此次重回无意义,无需进行request请求 + } else { + // 前提:宽高值均有效,值>0. 条件1:当前宽高与上一次宽高不同 条件2:当前是第一次绘制 + if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) { + LogUtil.log("execute request:width=" + this.currentWidth + " height= " + this.currentHeight) + ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) + } } }) } + watchImageKnifeOption() { + if (this.request !== undefined) { + this.request.requestState = ImageKnifeRequestState.DESTROY + } + this.request = undefined + this.componentVersion++ + ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) + } + getCurrentContext(): common.UIAbilityContext { if (this.currentContext == undefined) { this.currentContext = getContext(this) as common.UIAbilityContext @@ -143,10 +132,24 @@ export struct ImageKnifeComponent { return //针对reuse场景,不显示历史图片 } this.pixelMap = pixelMap - if (typeof this.pixelMap !== 'string' && this.imageKnifeOption.objectFit === ImageFit.Auto) { //针对静态图高度自适应 - let info = await this.pixelMap.getImageInfo() - this.adaptiveWidth = this.currentWidth - this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width + if (typeof this.pixelMap !== 'string') { + if (this.imageKnifeOption.objectFit === ImageFit.Auto) { + let info = await this.pixelMap.getImageInfo() + + this.adaptiveWidth = this.currentWidth + this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width + + // if (this.currentWidth / this.currentHeight > info.size.width / info.size.height) { + // this.adaptiveWidth = this.currentWidth + // this.adaptiveHeight = info.size.height * this.currentWidth / this.currentHeight + // } + // else { + // this.adaptiveWidth = info.size.width * this.currentWidth / this.currentHeight + // this.adaptiveHeight = this.currentHeight + // } + } + } else { + //console.info("KKKKKKKKKKK:" + pixelMap) } if (requestSource == ImageKnifeRequestSource.SRC) { @@ -165,4 +168,8 @@ export struct ImageKnifeComponent { return this.request } +} + +interface KeyCanvas { + keyId: string } \ No newline at end of file diff --git a/library/src/main/ets/model/ImageKnifeOption.ets b/library/src/main/ets/model/ImageKnifeOption.ets index 5c5f292..974b53b 100644 --- a/library/src/main/ets/model/ImageKnifeOption.ets +++ b/library/src/main/ets/model/ImageKnifeOption.ets @@ -22,55 +22,38 @@ export interface HeaderOptions { key: string; value: Object; } -interface AnimatorType { - state?: AnimationStatus - iterations?: number - reverse?: boolean - onStart?:()=>void - onFinish?:()=>void - onPause?:()=>void - onCancel?:()=>void - onRepeat?:()=>void -} -@ObservedV2 + +@Observed export class AnimatorOption { - @Trace + @Track state?: AnimationStatus = AnimationStatus.Running - @Trace + @Track iterations?: number = -1 - @Trace + @Track reverse?: boolean = false - @Trace + @Track onStart?:()=>void - @Trace + @Track onFinish?:()=>void - @Trace + @Track onPause?:()=>void - @Trace + @Track onCancel?:()=>void - @Trace + @Track onRepeat?:()=>void - constructor(option?:AnimatorType) { - this.state = option?.state - this.iterations = option?.iterations - this.reverse = option?.reverse - this.onStart = option?.onStart - this.onFinish = option?.onFinish - this.onPause = option?.onPause - this.onCancel = option?.onCancel - this.onRepeat = option?.onRepeat - } } -interface ImageOption { + +@Observed +export class ImageKnifeOption { // 主图资源 - loadSrc: string | PixelMap | Resource + loadSrc: string | PixelMap | Resource = ""; // 占位图 - placeholderSrc?: string | PixelMap | Resource + placeholderSrc?: string | PixelMap | Resource; // 失败占位图 - errorholderSrc?: string | PixelMap | Resource + errorholderSrc?: string | PixelMap | Resource; headerOption?: Array; // 自定义缓存关键字 - signature?: string + signature?: string; // 主图填充效果 objectFit?: ImageFit // 占位图填充效果 @@ -82,65 +65,16 @@ interface ImageOption { // 缓存策略 writeCacheStrategy?: CacheStrategy // 仅使用缓存加载数据 - onlyRetrieveFromCache?: boolean; - priority?: taskpool.Priority + onlyRetrieveFromCache?: boolean = false; + priority?: taskpool.Priority = taskpool.Priority.LOW context?: common.UIAbilityContext; progressListener?: (progress: number) => void; transformation?: PixelMapTransformation onLoadListener?: OnLoadCallBack | undefined; onComplete?:(event:EventImage | undefined) => void drawingColorFilter?: ColorFilter | drawing.ColorFilter -} -@ObservedV2 -export class ImageKnifeOption { - // 主图资源 - @Trace loadSrc: string | PixelMap | Resource = ""; - // 占位图 - placeholderSrc?: string | PixelMap | Resource; - // 失败占位图 - errorholderSrc?: string | PixelMap | Resource; - headerOption?: Array; - // 自定义缓存关键字 - @Trace signature?: string; - // 主图填充效果 - @Trace objectFit?: ImageFit - // 占位图填充效果 - placeholderObjectFit?: ImageFit - // 错误图填充效果 - errorholderObjectFit?: ImageFit - customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise - @Trace border?: BorderOptions - // 缓存策略 - writeCacheStrategy?: CacheStrategy - // 仅使用缓存加载数据 - onlyRetrieveFromCache?: boolean = false; - priority?: taskpool.Priority = taskpool.Priority.LOW - context?: common.UIAbilityContext; - progressListener?: (progress: number) => void; - @Trace transformation?: PixelMapTransformation - onLoadListener?: OnLoadCallBack | undefined; - onComplete?:(event:EventImage | undefined) => void - drawingColorFilter?: ColorFilter | drawing.ColorFilter - constructor(option?:ImageOption) { - this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc - this.placeholderSrc = option?.placeholderSrc - this.errorholderSrc = option?.errorholderSrc - this.headerOption = option?.headerOption - this.signature = option?.signature - this.objectFit = option?.objectFit - this.placeholderObjectFit = option?.placeholderObjectFit - this.errorholderObjectFit = option?.errorholderObjectFit - this.customGetImage = option?.customGetImage - this.border = option?.border - this.writeCacheStrategy = option?.writeCacheStrategy - this.onlyRetrieveFromCache = option?.onlyRetrieveFromCache - this.priority = option?.priority - this.context = option?.context - this.progressListener = option?.progressListener - this.transformation = option?.transformation - this.onLoadListener = option?.onLoadListener - this.onComplete = option?.onComplete - this.drawingColorFilter = option?.drawingColorFilter + constructor() { + } } diff --git a/sharedlibrary/src/main/ets/pages/Index.ets b/sharedlibrary/src/main/ets/pages/Index.ets index 92d223f..3bd9a0a 100644 --- a/sharedlibrary/src/main/ets/pages/Index.ets +++ b/sharedlibrary/src/main/ets/pages/Index.ets @@ -14,11 +14,11 @@ */ import { ImageKnife , ImageKnifeComponent ,ImageKnifeOption } from "@ohos/imageknife" -@ComponentV2 +@Component export struct IndexComponent { - @Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ + @State imageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon') - }) + } build() { Column() { Button($r('app.string.Preload')).onClick((event: ClickEvent) => {