uni-app App端图片手势缩放默认不生效,因uni.previewImage在iOS/Android使用原生相册控件,仅支持全屏预览,不支持双指缩放与拖拽;需自行实现带touch事件的手势查看器。
原因是 uni.previewImage App 端(iOS/Android)底层采用原生相册控件,只能进行「全屏预览」,并不支持双指缩放、拖拽等手势,也不是「可交互画布」。若要实现真正的手势缩放,就必须绕开 uni.previewImage,自行制作支持手势控制的图片查看器。
uni-app 原生组件并结合 @touchstart/@touchmove 完成基础缩放主要思路是使用 <image> 搭配 transform: scale() 和 translate() 双指间距的增减与偏移量先由 touch 事件求出,据此动态调整位移和缩放。真正的难点并非“能写”,而是同时做到“别失焦、别越界、别卡顿”本身:
<image> 外层添加 overflow: hidden 容器,否则图片缩放后被拖出边界时,会带动页面滚动touches[0] 和 touches[1] 求得初始距离,再与 changedTouches 距离差进行比较,不能仅依据单点位移(x1 + x2) / 2 和 (y1 + y2) / 2 中心位置确定后,以反向补偿的方式执行 translatetransform 在 <image> 上的兼容性尚可,不过一定要添加 will-change: transform 以提高渲染帧率scale 和 maxScale 应当怎样设置才合理缩放上限不能随意确定。设得太小(如 maxScale: 2),用户会认为不够;设得太大(如 5),则会造成像素拉伸模糊和内存激增,特别是在低端 Android 设备上,容易出现 OOM 或卡死:
1.5,最大值设置为 3.5 ——既能满足绝大多数高清图片的细节查看需求,也可避开高倍缩放带来的性能问题scale 不应固定写成 1,初始缩放值不能固定:先结合屏幕尺寸与图片宽高比判断应「适应高度」还是「适应宽度」,再动态计算,才能避免开启时留下大片黑边Math.min/Math.max 进行强制约束 scale 范围,避免连续快速缩放引起数值溢出transform: scale(0.1) 这类极小值会触发渲染 bug,minScale 建议不要低于 0.6
如果在 pages.json 中没有关闭下拉刷新,也未禁用 scroll-view 滚动,或者父容器使用了 catchtouchmove,图片手势都可能失效或发生错乱:
z-index: 9999 属于稳妥做法;相比H5,App 端对 z-index 行为更为敏感event.preventDefault(),并把 catchtouchmove 到容器上,避免事件流被 Android 截获后转去执行页面滚动tap 事件(依据两次 tap 用于判断时间间隔的 dbclick —— 该事件无法在 App 端使用transform 样式,并重置 scale 和 translate 变量,以免再次打开时沿用上一次的状态手势缩放表面上并不复杂,但真正实现时必须同时保证三点:事件不丢、缩放不飘、动画不卡。App 端不像浏览器那样宽容,一个 transform 位置写错,或缺少一个 preventDefault,都会让整个使用体验崩坏。