Only grab InteractionManager handle in PanResponder, not all touches
Summary: Previously, `InteractionManager` was baked in at the lowest level to all touches via `ResponderEventPlugin`, which meant that any time a finger was touching the screen, `InteractionManager` would be locked. This included while doing 100% native scrolls, and thus would block progress from Relay, Incremental, or anything else scheduling events through `InteractionManager`. This diff switches to only bake it into `PanResponder` (and it remains hooked into `Animated` as before) which are the main two cases where we need 60fps JS execution and want to queue up slower tasks. This is done with a reusable higher-order-responder `InteractionManager.createResponderClass`. Depends on FYI https://github.com/facebook/react/pull/6587, https://github.com/facebook/react/pull/6584 Reviewed By: sebmarkbage Differential Revision: D3210951 fb-gh-sync-id: 682d21ac5cff704673b63d5942a903a3d8912835 fbshipit-source-id: 682d21ac5cff704673b63d5942a903a3d8912835
This commit is contained in:
parent
c05169d8b7
commit
667d278119
|
@ -119,6 +119,56 @@ var InteractionManager = {
|
|||
_deleteInteractionSet.add(handle);
|
||||
},
|
||||
|
||||
/**
|
||||
* Can be used to turn a regular repsonder into one that holds interaction handles
|
||||
* when the responder is granted. This makes it easier to acheive 60fps responder
|
||||
* interactions in JS, e.g. for drag-and-drop gestures with PanResponder.
|
||||
*/
|
||||
createResponderFactory(baseResponderFactory: {create: (config: Object) => Object}) {
|
||||
function clearInteractionHandle(
|
||||
interactionState: {handle: ?Handle},
|
||||
callback: Function,
|
||||
event: Object,
|
||||
gestureState: Object
|
||||
) {
|
||||
if (interactionState.handle) {
|
||||
InteractionManager.clearInteractionHandle(interactionState.handle);
|
||||
interactionState.handle = null;
|
||||
}
|
||||
if (callback) {
|
||||
callback(event, gestureState);
|
||||
}
|
||||
}
|
||||
return {
|
||||
create: function(config: Object) {
|
||||
const interactionState = {
|
||||
handle: (null: ?Handle),
|
||||
};
|
||||
const newConfig = {
|
||||
...config,
|
||||
onPanResponderGrant: function (e, gestureState) {
|
||||
if (!interactionState.handle) {
|
||||
interactionState.handle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
if (config.onPanResponderGrant) {
|
||||
config.onPanResponderGrant(e, gestureState);
|
||||
}
|
||||
},
|
||||
onPanResponderReject: function (e, gestureState) {
|
||||
clearInteractionHandle(interactionState, config.onPanResponderReject, e, gestureState);
|
||||
},
|
||||
onPanResponderRelease: function (e, gestureState) {
|
||||
clearInteractionHandle(interactionState, config.onPanResponderRelease, e, gestureState);
|
||||
},
|
||||
onPanResponderTerminate: function (e, gestureState) {
|
||||
clearInteractionHandle(interactionState, config.onPanResponderTerminate, e, gestureState);
|
||||
},
|
||||
};
|
||||
return baseResponderFactory.create(newConfig);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
addListener: _emitter.addListener.bind(_emitter),
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var InteractionManager = require('./InteractionManager');
|
||||
var TouchHistoryMath = require('TouchHistoryMath');
|
||||
|
||||
var currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
||||
|
@ -25,6 +26,9 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
|
|||
* single-touch gestures resilient to extra touches, and can be used to
|
||||
* recognize simple multi-touch gestures.
|
||||
*
|
||||
* By default, `PanResponder` holds an `InteractionManager handle to block
|
||||
* long-running JS events from interrupting active gestures.
|
||||
*
|
||||
* It provides a predictable wrapper of the responder handlers provided by the
|
||||
* [gesture responder system](docs/gesture-responder-system.html).
|
||||
* For each handler, it provides a new `gestureState` object alongside the
|
||||
|
@ -275,15 +279,19 @@ var PanResponder = {
|
|||
create: function (config) {
|
||||
var gestureState = {
|
||||
// Useful for debugging
|
||||
stateID: Math.random()
|
||||
stateID: Math.random(),
|
||||
};
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
var panHandlers = {
|
||||
onStartShouldSetResponder: function (e) {
|
||||
return config.onStartShouldSetPanResponder === undefined ? false : config.onStartShouldSetPanResponder(e, gestureState);
|
||||
return config.onStartShouldSetPanResponder === undefined ?
|
||||
false :
|
||||
config.onStartShouldSetPanResponder(e, gestureState);
|
||||
},
|
||||
onMoveShouldSetResponder: function (e) {
|
||||
return config.onMoveShouldSetPanResponder === undefined ? false : config.onMoveShouldSetPanResponder(e, gestureState);
|
||||
return config.onMoveShouldSetPanResponder === undefined ?
|
||||
false :
|
||||
config.onMoveShouldSetPanResponder(e, gestureState);
|
||||
},
|
||||
onStartShouldSetResponderCapture: function (e) {
|
||||
// TODO: Actually, we should reinitialize the state any time
|
||||
|
@ -292,7 +300,9 @@ var PanResponder = {
|
|||
PanResponder._initializeGestureState(gestureState);
|
||||
}
|
||||
gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
|
||||
return config.onStartShouldSetPanResponderCapture !== undefined ? config.onStartShouldSetPanResponderCapture(e, gestureState) : false;
|
||||
return config.onStartShouldSetPanResponderCapture !== undefined ?
|
||||
config.onStartShouldSetPanResponderCapture(e, gestureState) :
|
||||
false;
|
||||
},
|
||||
|
||||
onMoveShouldSetResponderCapture: function (e) {
|
||||
|
@ -304,7 +314,9 @@ var PanResponder = {
|
|||
return false;
|
||||
}
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
return config.onMoveShouldSetPanResponderCapture ? config.onMoveShouldSetPanResponderCapture(e, gestureState) : false;
|
||||
return config.onMoveShouldSetPanResponderCapture ?
|
||||
config.onMoveShouldSetPanResponderCapture(e, gestureState) :
|
||||
false;
|
||||
},
|
||||
|
||||
onResponderGrant: function (e) {
|
||||
|
@ -312,24 +324,34 @@ var PanResponder = {
|
|||
gestureState.y0 = currentCentroidY(e.touchHistory);
|
||||
gestureState.dx = 0;
|
||||
gestureState.dy = 0;
|
||||
if (config.onPanResponderGrant) config.onPanResponderGrant(e, gestureState);
|
||||
if (config.onPanResponderGrant) {
|
||||
config.onPanResponderGrant(e, gestureState);
|
||||
}
|
||||
// TODO: t7467124 investigate if this can be removed
|
||||
return config.onShouldBlockNativeResponder === undefined ? true : config.onShouldBlockNativeResponder();
|
||||
return config.onShouldBlockNativeResponder === undefined ?
|
||||
true :
|
||||
config.onShouldBlockNativeResponder();
|
||||
},
|
||||
|
||||
onResponderReject: function (e) {
|
||||
if (config.onPanResponderReject) config.onPanResponderReject(e, gestureState);
|
||||
if (config.onPanResponderReject) {
|
||||
config.onPanResponderReject(e, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderRelease: function (e) {
|
||||
if (config.onPanResponderRelease) config.onPanResponderRelease(e, gestureState);
|
||||
if (config.onPanResponderRelease) {
|
||||
config.onPanResponderRelease(e, gestureState);
|
||||
}
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderStart: function (e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
if (config.onPanResponderStart) config.onPanResponderStart(e, gestureState);
|
||||
if (config.onPanResponderStart) {
|
||||
config.onPanResponderStart(e, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderMove: function (e) {
|
||||
|
@ -342,13 +364,17 @@ var PanResponder = {
|
|||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
if (config.onPanResponderMove) config.onPanResponderMove(e, gestureState);
|
||||
if (config.onPanResponderMove) {
|
||||
config.onPanResponderMove(e, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderEnd: function (e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
if (config.onPanResponderEnd) config.onPanResponderEnd(e, gestureState);
|
||||
if (config.onPanResponderEnd) {
|
||||
config.onPanResponderEnd(e, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderTerminate: function (e) {
|
||||
|
@ -359,11 +385,13 @@ var PanResponder = {
|
|||
},
|
||||
|
||||
onResponderTerminationRequest: function (e) {
|
||||
return config.onPanResponderTerminationRequest === undefined ? true : config.onPanResponderTerminationRequest(e, gestureState);
|
||||
return config.onPanResponderTerminationRequest === undefined ?
|
||||
true :
|
||||
config.onPanResponderTerminationRequest(e, gestureState);
|
||||
}
|
||||
};
|
||||
return { panHandlers: panHandlers };
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PanResponder;
|
||||
module.exports = InteractionManager.createResponderFactory(PanResponder);
|
||||
|
|
Loading…
Reference in New Issue