Skip to content

Commit 0ef398b

Browse files
author
梁栋
committed
support multi-touch
1 parent 856818c commit 0ef398b

2 files changed

Lines changed: 65 additions & 18 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ If you have problems with this plugin, then just create an issue, and I will sol
1919
* *Simple API*: only need to provide your data-callback-function, the plugin will do the left.
2020
* *Configurable*: you can specific the position where "refresh/load" will be triggered, the images that show up...But the default config already works well.
2121
* *Flexibility*: "pull-down/pull-up" features can be "open/close" separately, and "pull-up-to-load" anamition can be added by yourself additionaly.
22+
* *Experience*: in line with user's operating habits, strongly support multi-touch.
2223

2324
# Dependency
2425
* *iscroll5*: high performance, small footprint, dependency free, multi-platform javascript scroller.
@@ -145,6 +146,7 @@ You may need to load data for the first screen in app without user's touch, the
145146
* 简单的接口:用户仅需提供数据回调函数,框架负责剩余任务
146147
* 参数化配置:用户可自定义"下拉/上拉"的触发位置、图片等,但是默认值通常可以满足需求
147148
* 灵活的设定:"下拉/上拉"特性可独立"开启/关闭","上拉加载"特效交由用户订制
149+
* 良好的体验:拖拽行为符合用户习惯,支持强大的多点触摸
148150

149151
# 依赖
150152
* iscroll5:兼容各移动平台的滚动条方案

pullToRefresh.js

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
*/
1414
$.installPullToRefresh =
1515
function (container, option) {
16-
// 上一次移动的位置
17-
var touchLastY = null;
1816
// 当前的触摸事件
1917
var touchEvent = null;
2018
// 当前的刷新事件
@@ -23,6 +21,8 @@ function (container, option) {
2321
var curY = -55;
2422
// 当前的加载事件
2523
var loadEvent = null;
24+
// 正在触屏的手指数量
25+
var touchFinger = 0;
2626

2727
// 默认参数
2828
var defaultOption = {
@@ -181,45 +181,75 @@ function (container, option) {
181181
}
182182
}
183183

184+
// 更新最新的手指集合
185+
// 浏览器对changedTouches的实现存在问题, 因此总是使用全量的touches进行比对
186+
function compareTouchFingers(event) {
187+
var identSet = {};
188+
// 将不存在手指的添加到集合中
189+
for (var i = 0; i < event.originalEvent.touches.length; ++i) {
190+
var touch = event.originalEvent.touches[i];
191+
identSet[touch.identifier] = true;
192+
if (touchEvent[touch.identifier] === undefined) {
193+
touchEvent[touch.identifier] = null;
194+
++touchFinger;
195+
}
196+
}
197+
// 将已删除的手指集合清理
198+
for (var identifier in touchEvent) {
199+
// 浏览器集合中已不存在,删除
200+
if (identSet[identifier] === undefined) {
201+
delete(touchEvent[identifier]);
202+
--touchFinger;
203+
}
204+
}
205+
}
206+
184207
// 父容器注册下拉事件
185208
$(container).on("touchstart", function (event) {
186-
// 新的触摸事件
187-
touchEvent = {};
188-
// 有一个刷新事件正在进行
209+
if (!touchEvent) {
210+
// 第一根指头触屏, 产生新的触摸事件
211+
touchEvent = {};
212+
}
213+
// 将本次的手指加入到触摸事件集合中
214+
compareTouchFingers(event);
215+
216+
// 刷新事件正在进行,忽略本次触屏
189217
if (refreshEvent) {
190218
return;
191219
}
192220

193-
// 一个新的刷新事件
221+
// 产生新的刷新事件
194222
refreshEvent = touchEvent;
195-
// 重置下拉启动时的手势位置
196-
touchLastY = null;
197223
// 如果存在,则关闭回弹动画与相关监听
198224
pullToRefresh.removeClass("backTranTop");
199225
pullToRefresh.unbind();
200226
// 切换为pull图
201227
pullImg.attr("src", finalOption.pullImg);
202228
}).on("touchmove", function (event) {
203-
var touchCurY = event.originalEvent.changedTouches[0].clientY;
204-
205229
// 在刷新未完成前触摸,将被忽略
206230
if (touchEvent != refreshEvent) {
207231
return;
208232
}
209233

210234
// 滚动条必须到达顶部,才开始下拉刷新动画
235+
var maxDelta = 0;
211236
if (iscroll.y != 0) {
212237
return;
213-
} else if (touchLastY === null) {
214-
touchLastY = touchCurY; // 下拉启动时的手势位置
238+
} else { // 计算每个变化的手指, 取变化最大的delta
239+
for (var i = 0; i < event.originalEvent.changedTouches.length; ++i) {
240+
var fingerTouch = event.originalEvent.changedTouches[i];
241+
if (touchEvent[fingerTouch.identifier] !== null) {
242+
var delta = fingerTouch.clientY - touchEvent[fingerTouch.identifier];
243+
if (Math.abs(delta) > Math.abs(maxDelta)) {
244+
maxDelta = delta;
245+
}
246+
}
247+
touchEvent[fingerTouch.identifier] = fingerTouch.clientY;
248+
}
215249
}
216250

217-
// 计算与前一次事件之间移动的距离
218-
var delta = touchCurY - touchLastY;
219-
touchLastY = touchCurY;
220-
221251
// 图标的目标位置
222-
var destY = curY + delta;
252+
var destY = curY + maxDelta;
223253
// 向下不能拉出范围
224254
if (destY > finalOption.lowerBound) {
225255
destY = finalOption.lowerBound;
@@ -237,8 +267,23 @@ function (container, option) {
237267
iscroll.unlockScrollUp();
238268
}
239269
}).on("touchend touchcancel", function (event) {
270+
// 从touchEvent移除手指对应的记录
271+
compareTouchFingers(event);
272+
273+
var touchEventRef = touchEvent;
274+
275+
// 所有手指都离开, 则当前触摸事件结束
276+
if (!touchFinger) {
277+
touchEvent = null;
278+
}
279+
240280
// 在刷新未完成前触摸,将被忽略
241-
if (touchEvent != refreshEvent) {
281+
if (touchEventRef != refreshEvent) {
282+
return;
283+
}
284+
285+
// 只有所有手指都离开后, 才开始刷新动作
286+
if (touchFinger) {
242287
return;
243288
}
244289

0 commit comments

Comments
 (0)