|
41 | 41 | */ |
42 | 42 | @implementation RNGestureHandlerButton { |
43 | 43 | CALayer *_underlayLayer; |
| 44 | + BOOL _isTouchInsideBounds; |
44 | 45 | } |
45 | 46 |
|
46 | 47 | - (void)commonInit |
47 | 48 | { |
| 49 | + _isTouchInsideBounds = NO; |
48 | 50 | _hitTestEdgeInsets = UIEdgeInsetsZero; |
49 | 51 | _userEnabled = YES; |
50 | 52 | _pointerEvents = RNGestureHandlerPointerEventsAuto; |
@@ -275,6 +277,64 @@ - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event |
275 | 277 | return CGRectContainsPoint(hitFrame, point); |
276 | 278 | } |
277 | 279 |
|
| 280 | +- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event |
| 281 | +{ |
| 282 | + _isTouchInsideBounds = YES; |
| 283 | + return [super beginTrackingWithTouch:touch withEvent:event]; |
| 284 | +} |
| 285 | + |
| 286 | +- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event |
| 287 | +{ |
| 288 | + // DO NOT call super. We are entirely taking over the drag event generation. |
| 289 | + |
| 290 | + CGPoint location = [touch locationInView:self]; |
| 291 | + CGRect hitFrame = UIEdgeInsetsInsetRect(self.bounds, self.hitTestEdgeInsets); |
| 292 | + BOOL currentlyInside = CGRectContainsPoint(hitFrame, location); |
| 293 | + |
| 294 | + if (currentlyInside) { |
| 295 | + if (!_isTouchInsideBounds) { |
| 296 | + [self sendActionsForControlEvents:UIControlEventTouchDragEnter]; |
| 297 | + _isTouchInsideBounds = YES; |
| 298 | + } |
| 299 | + |
| 300 | + // Targets may call `cancelTrackingWithEvent:` in response to DragEnter. |
| 301 | + if (self.tracking) { |
| 302 | + [self sendActionsForControlEvents:UIControlEventTouchDragInside]; |
| 303 | + } |
| 304 | + } else { |
| 305 | + if (_isTouchInsideBounds) { |
| 306 | + [self sendActionsForControlEvents:UIControlEventTouchDragExit]; |
| 307 | + _isTouchInsideBounds = NO; |
| 308 | + } |
| 309 | + |
| 310 | + // Targets may call `cancelTrackingWithEvent:` in response to DragExit. |
| 311 | + if (self.tracking) { |
| 312 | + [self sendActionsForControlEvents:UIControlEventTouchDragOutside]; |
| 313 | + } |
| 314 | + } |
| 315 | + |
| 316 | + // If `cancelTrackingWithEvent` was called, `self.tracking` will be NO. |
| 317 | + return self.tracking; |
| 318 | +} |
| 319 | + |
| 320 | +- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event |
| 321 | +{ |
| 322 | + // Also bypass super here so that the final "up" event respects the |
| 323 | + // strict bounds, rather than Apple's 70-point. |
| 324 | + |
| 325 | + if (touch != nil) { |
| 326 | + CGPoint location = [touch locationInView:self]; |
| 327 | + CGRect hitFrame = UIEdgeInsetsInsetRect(self.bounds, self.hitTestEdgeInsets); |
| 328 | + if (CGRectContainsPoint(hitFrame, location)) { |
| 329 | + [self sendActionsForControlEvents:UIControlEventTouchUpInside]; |
| 330 | + } else { |
| 331 | + [self sendActionsForControlEvents:UIControlEventTouchUpOutside]; |
| 332 | + } |
| 333 | + } |
| 334 | + |
| 335 | + _isTouchInsideBounds = NO; |
| 336 | +} |
| 337 | + |
278 | 338 | - (RNGHUIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event |
279 | 339 | { |
280 | 340 | RNGestureHandlerPointerEvents pointerEvents = _pointerEvents; |
|
0 commit comments