1# 多图片预览效果实现 2 3### 介绍 4 5图片预览在应用开发中是一种常见场景,这里实现了对于图片的 缩放、移动、旋转、多图片预览功能做了处理。 6 7### 效果图预览 8 9| 图片预览 | 10|------------------------------------------------------------------| 11| <img src="screenshots/picturepreview_example.gif" width="300" /> | 12 13 14**使用说明:** 15 161. 双指捏合对图片进行缩放 172. 双击图片进行图片的大小切换,在放大状态下,双击可恢复默认状态 183. 图片在放大模式下,滑动图片查看图片的对应位置 194. 点击切换图片底图颜色 205. 双指旋转对图片进行旋转 21 22### 工程目录 23 24``` 25|entry/src/main/ets 26| |---entryablity 27| | |---EntryAbility.ts // 程序入口类 28| |---constants // 常量 29| |---model // 自定义数据模型 30| |---utils // 工具类 31| |---picturepreviewsample // 示例使用 32| | |---PicturePreviewSample.ets // 场景构建案例 33| |---view // 图片预览方案涉及的主要组件 34| | |---PicturePreview.ets // 图片预览组件 35| | |---PicturePreviewImage.ets // 单张图片的显示组件 36``` 37 38### 实现思路 39 401. 使用matrix实现图片的缩放。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 41 ```typescript 42 @State matrix: matrix4.Matrix4Transit = matrix4.identity().copy(); 43 Image(this.imageUrl) 44 .transform(this.matrix) 45 ``` 462. 使用offset属性对图片进行偏移。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 47 ```typescript 48 @State imageOffsetInfo: OffsetModel = new OffsetModel(0, 0); 49 Image(this.imageUrl) 50 .offset({ 51 x: this.imageOffsetInfo.currentX, 52 y: this.imageOffsetInfo.currentY 53 }) 54 ``` 553. Image的objectFit属性设置为Cover,锁定图片宽高比,并使其能够超出父组件边界显示。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 56 ```typescript 57 Image(this.imageUrl) 58 .objectFit(ImageFit.Cover) 59 ``` 604. 提前计算图片信息,并通过Image的宽或高配合aspectRatio设置默认尺寸。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 61 ```typescript 62 Image(this.imageUrl) 63 .width(this.fitWH === "width" ? $r("app.string.image_default_width") : undefined) 64 .height(this.fitWH === "height" ? $r("app.string.image_default_height") : undefined) 65 .aspectRatio(this.imageWHRatio) 66 .onComplete((event) => { 67 if (event) { 68 let imageW = event.width; 69 let imageH = event.height; 70 let windowSize = windowSizeManager.get(); 71 // 图片宽高比 72 this.imageWHRatio = imageW / imageH; 73 // 图片默认大小 74 this.imageDefaultSize = this.calcImageDefaultSize(this.imageWHRatio, windowSize); 75 // 图片宽度 等于 视口宽度 则图片使用宽度适配 否则 使用 高度适配 76 if (this.imageDefaultSize.width === windowSize.width) { 77 this.imageWH = ImageWH.width; 78 } else { 79 this.imageWH = ImageWH.height; 80 } 81 /** 82 * 1.5 的基本倍数上添加 撑满全屏需要多少倍数 83 * 1.5 是初始化时候给的值 84 * 在1.5上面加是为了让图片可以放的更大 85 */ 86 this.imageScaleInfo.maxScaleValue += this.imageWH === ImageWH.width ? 87 (windowSize.height / this.imageDefaultSize.height) : 88 (windowSize.width / this.imageDefaultSize.width); 89 } 90 }) 91 ``` 925. 通过滑动手势来处理图片位置和边界判定。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 93 ```typescript 94 Image(this.imageUrl) 95 .gesture( 96 GestureGroup( 97 GestureMode.Exclusive, 98 // TODO:知识点:滑动图片 99 PanGesture({ fingers: 1 }) 100 .onActionUpdate((event: GestureEvent) => { 101 if (this.imageWH != ImageWH.default) { 102 this.setCrossAxis(event); 103 this.setPrincipalAxis(event); 104 } 105 }) 106 .onActionEnd((event: GestureEvent) => { 107 this.imageOffsetInfo.stash(); 108 this.evaluateBound(); 109 }) 110 111 ) 112 ) 113 ``` 1146. 通过旋转手势来处理图片旋转方向。详情见[PicturePreviewImage.ets](entry/src/main/ets/view/PicturePreviewImage.ets)。 115 ```typescript 116 Image(this.imageUrl) 117 .gesture( 118 GestureGroup( 119 GestureMode.Exclusive, 120 // TODO:知识点:双指旋转图片 121 RotationGesture({ angle: this.imageRotateInfo.startAngle }) 122 .onActionUpdate((event: GestureEvent) => { 123 let angle = this.imageRotateInfo.lastRotate + event.angle; 124 if (event.angle > 0) { 125 angle -= this.imageRotateInfo.startAngle; 126 } else { 127 angle += this.imageRotateInfo.startAngle; 128 } 129 this.matrix = matrix4.identity() 130 .scale({ 131 x: this.imageScaleInfo.scaleValue, 132 y: this.imageScaleInfo.scaleValue 133 }) 134 .rotate({ 135 x: 0, 136 y: 0, 137 z: 1, 138 angle: angle, 139 }).copy(); 140 this.imageRotateInfo.currentRotate = angle; 141 }) 142 .onActionEnd((event: GestureEvent) => { 143 let rotate = simplestRotationQuarter(this.imageRotateInfo.currentRotate); 144 runWithAnimation(() => { 145 this.imageRotateInfo.currentRotate = rotate; 146 this.matrix = matrix4.identity() 147 .rotate({ 148 x: 0, 149 y: 0, 150 z: 1, 151 angle: this.imageRotateInfo.currentRotate, 152 }).copy(); 153 this.imageRotateInfo.stash(); 154 this.imageScaleInfo.reset(); 155 this.imageOffsetInfo.reset(); 156 }) 157 }) 158 159 ) 160 ) 161 ``` 162 163### 相关权限 164 165不涉及 166 167### 依赖 168 169不涉及 170 171### 约束与限制 172 1731. 本示例仅支持标准系统上运行。 174 1752. 本示例为Stage模型,从API version 12开始支持。SDK版本号:5.0.0.71 Release,镜像版本号:OpenHarmony 5.0.1.107。 176 1773. 本示例需要使用DevEco Studio 5.0.2 Release (Build Version: 5.0.7.200, built on January 23, 2025)编译运行。 178 179### 下载 180 181如需单独下载本工程,执行如下命令: 182 183```shell 184git init 185git config core.sparsecheckout true 186echo code/UI/ImageViewer/ > .git/info/sparse-checkout 187git remote add origin https://gitee.com/openharmony/applications_app_samples.git 188git pull origin master 189``` 190 191### 参考资料 192 1931. [image](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-basic-components-image.md) 194 1952. [gesture](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-gesture-settings.md) 196 1973. [list](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-container-list.md) 198 1994. [window](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/js-apis-window.md) 200 2015. [matrix4](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/js-apis-matrix4.md)