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