# 微信小程序中实现手势缩放图片

- 作者：严灏
- 发布时间：2016-11-02 09:44
- 原文：https://www.ifanr.com/minapp/740404

![feature-1](https://s3.ifanr.com/wp-content/uploads/2016/11/feature-1.jpg)

在开发「知了地铁」小程序的时候，我们发现：在几寸的手机屏幕上完整显示地铁线网图，用户就很难看清细节；而默认将线网图按照 1:1 模式显示出来，用户需要多次拖动才能看到线网图的概况。

很明显，两种实现方式的体验，都非常糟糕。

![scale-1](https://s3.ifanr.com/wp-content/uploads/2016/11/scale-1.jpg)

因此，如果要在小程序中展示带有细节信息的图片（例如地铁线网图），就需要为其加上缩放功能。而用双指张合手势进行缩放，是大部分智能手机用户都已经习惯了的缩放方法。

今天，知晓程序就为大家带来有关手势缩放功能的实现方法，以及手势缩放实现在小程序中的局限和问题。

关注知晓程序（微信号 zxcx0101），回复「知了地铁」，抢先看「知了地铁」小程序上手体验文章。

### 手势动态检测

首先，我们需要获得用户的触摸事件。只有获得了这个事件，小程序才能得知用户希望缩放图片，同时确定图片的缩放倍数。

我们发现微信提供 touchmove 事件，在用户触摸屏幕并在屏幕上移动手指时，这个事件就会被触发。

手势缩放的核心思想是：根据两只手指相对距离的变化来对图片进行放大或缩小。因此，我们需要知道两只手指相对距离的变化，才能做到良好的缩放体验。

`touchmove` 事件可以实现的功能，大致可以总结为：

- 手指在屏幕上进行移动时，对应的组件上就会以 16 ms 一次的频率不断触发 `touchmove` 事件；
- 手指离开屏幕后，则会触发 `touchend` 事件。

`touchmove` 事件所包含的事件对象中有一个 `touches` 属性，此属性为当前停留在屏幕中的触摸点信息的数组。触摸点的信息包括：

- `identifier`：触摸点的标志符；
- `pageX` 和 `pageY`：距离文档左上角的距离；
- `clientX` 和 `clientY`：距离屏幕可显示区域左上角距离。

我们可以通过不断获取 `clientX` 和 `clientY` 数据的方式，来确定手指在屏幕上的位置变化。

```
xMove = e.touches[1].clientX - e.touches[0].clientX;
yMove = e.touches[1].clientY - e.touches[0].clientY;
distance = Math.sqrt(xMove * xMove + yMove * yMove);
```

`distance` 变量即为两只手指之间的距离。在 `touchmove` 被触发的时候，小程序就会计算一次 `distance`。

我们为新的 `distance` 变量定名为 `newDistance`，相应地，旧变量定名为 `oldDistance`。

之后，我们设定一个新的变量 `distanceDiff = newDistance - oldDistance`，它反映两次 `touchmove` 触发瞬间，两根手指相对距离的变化值。

`distanceDiff` 为正数时，表示两指间距离在变大，图片需要被放大；反之，则代表两指间距缩小，图片需要被缩小。

### 图片动态缩放

到这里，我们已经可以探测用户的手指距离变化了。接下来，我们需要根据用户的手势，确定图片缩放倍数，然后根据倍数缩放图片。

首先，要确定 `distance` 的变化值与图片放大或缩小的变化率相关联的规则。

我们将图片正常显示时的尺寸定为基准值，存放于变量 `baseWidth` 和 `baseHeight` 中。图片需要放大的倍数设置为变量 `scale`，它的初始值和最小值为 `1`，最大值可根据需要来设置。

经过多次试验，我们最后确定了一个公式：

```
newScale = oldScale + 0.005 * distanceDiff
```

此公式中的 `0.005` 为图片的缩放比例。在实测中，使用 0.005 这个值可获得比较良好的缩放体验。

现在，我们为图片对象绑定 `touchmove` 事件。在每次 `touchmove` 被触发后，我们都可以计算出新的图片需要被放大的倍数，我们将这个变量定名为 `scale`。

具体方式是：在每次 `touchmove` 被触发后，通过探测手指距离变化而得到的数据，来得到图片按比例缩放后的高宽值。

```
scaleWidth = scale * baseWidth;
scaleHeight = scale * baseHeight;
```

接下来，我们在 WXML 中，将图片对象的高和宽绑定相应的动态值，我们就能实现手势缩放功能了：

```
<image class = "image"
       src = "..."
       style = "width:{{ scaleWidth }}px; 
                height:{{ scaleHeight }}px">
```

![scale-2](https://s3.ifanr.com/wp-content/uploads/2016/11/scale-2.jpg)

### 用 `scroll-view`，还是用 `view`？

实现了图片的缩放之后，还需要一个容器存放图片。微信为视图组件提供了 &#96;scroll-view&#96; 和 &#96;view&#96; 两种容器容。但在目前阶段，两种容器都不能非常完美地实现手势缩放功能。

我们原本使用的方案是：利用 `scroll-view`，设置 `scroll-x` 和 `scroll-y` 属性为 `true`。这样做，可以在放大并滑动浏览图片时，拥有良好的浏览体验。

但是，我们发现 `scroll-view` 组件还存在缩放时出现界面闪动的现象的 bug。用双指手势缩放存在 `scroll-view` 容器中的图片，极易触发此 bug。

此问题只能等待微信官方进行修复。但在目前阶段，开发者也可以选择：

- 放弃 `scroll-view`，转而使用不带有良好滑动体验的 view 组件；
- 放弃使用手势缩放功能，转而开发「放大 – 缩小」按钮组件。

以上就是知晓程序（微信号 zxcx0101）带来的手势缩放图片功能的实现教程。虽然目前手势缩放并不能完美实现，但也希望大家可以举一反三，通过这个思路，创造出体验更好的小程序。

**本文由知晓程序原创出品，关注微信号 zxcx0101，回复「上手」获取全网最值得看的小程序上手体验系列文章。**

快速关注知晓程序↓↓↓

![zxcx](https://s3.ifanr.com/wp-content/uploads/2016/11/zxcx-1.jpg)**知晓程序（微信号 zxcx0101）是爱范儿旗下专注于小程序生态的公众号。我们提供最全面、新鲜的小程序资讯（消息、观点、指南、活动）和服务，在这里你能了解到关于小程序的一切。**
