Fabric: Proper implementation -[RCTSurfaceTouchHandler reset]

Summary:
Apparently, if a gesture recognizer got 'reset', OS does not call `touchesCancelled:` method, so we have to do it manually.
To implement this we have to split `_dispatchTouches:eventType:` into two methods: the first converts Objective-C touches to C++ touches, the second consumes that. We have to do this because during reset we don't have a collection of UIKit touches.

Reviewed By: mdvacca

Differential Revision: D13072807

fbshipit-source-id: 677e2febf9f96dcdfaadfadf5b9ab3893f93e796
This commit is contained in:
Valentin Shergin 2018-11-16 18:18:57 -08:00 committed by Facebook Github Bot
parent 868406dbec
commit 560652cfe8

View File

@ -209,16 +209,26 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
}
}
- (void)_dispatchTouches:(NSSet<UITouch *> *)touches eventType:(RCTTouchEventType)eventType
- (std::vector<ActiveTouch>)_activeTouchesFromTouches:(NSSet<UITouch *> *)touches
{
std::vector<ActiveTouch> activeTouches;
activeTouches.reserve(touches.count);
for (UITouch *touch in touches) {
activeTouches.push_back(_activeTouches.at(touch));
}
return activeTouches;
}
- (void)_dispatchActiveTouches:(std::vector<ActiveTouch>)activeTouches eventType:(RCTTouchEventType)eventType
{
TouchEvent event = {};
std::unordered_set<ActiveTouch, ActiveTouch::Hasher, ActiveTouch::Comparator> changedActiveTouches = {};
std::unordered_set<SharedTouchEventEmitter> uniqueEventEmitter = {};
BOOL isEndishEventType = eventType == RCTTouchEventTypeTouchEnd || eventType == RCTTouchEventTypeTouchCancel;
for (UITouch *touch in touches) {
const auto &activeTouch = _activeTouches[touch];
for (const auto &activeTouch : activeTouches) {
if (!activeTouch.eventEmitter) {
continue;
}
@ -276,7 +286,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesBegan:touches withEvent:event];
[self _registerTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchStart];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchStart];
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
@ -290,7 +301,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesMoved:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchMove];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchMove];
self.state = UIGestureRecognizerStateChanged;
}
@ -300,7 +312,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesEnded:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchEnd];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchEnd];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@ -315,7 +328,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesCancelled:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchCancel];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchCancel];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@ -327,10 +341,23 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
- (void)reset
{
// Technically, `_activeTouches` must be already empty at this point,
// but just to be sure, we clear it explicitly.
_activeTouches.clear();
_identifierPool.reset();
[super reset];
if (_activeTouches.size() != 0) {
std::vector<ActiveTouch> activeTouches;
activeTouches.reserve(_activeTouches.size());
for (auto const &pair : _activeTouches) {
activeTouches.push_back(pair.second);
}
[self _dispatchActiveTouches:activeTouches
eventType:RCTTouchEventTypeTouchCancel];
// Force-unregistering all the touches.
_activeTouches.clear();
_identifierPool.reset();
}
}
- (BOOL)canPreventGestureRecognizer:(__unused UIGestureRecognizer *)preventedGestureRecognizer