[ios] Force going through begin in state manager#3979
[ios] Force going through begin in state manager#3979akwasniewski wants to merge 6 commits intomainfrom
Conversation
|
Are you sure this doesn't remove all gesture relations on iOS? |
Ok, I trusted xcode, which said nobody calls those functions and they don't overload anything... I assumed they were obsolete, but I see they are indeed overloads from some iOS functions. My example which used gesture relations was also unaffected, neither was pressable but I see the lock example does not work now. |
Ok, in a89a631 I fixed StateManager by simply forcing states to go through the |
| } else if (state == 4) { // ACTIVE | ||
| if (handler.recognizer.state == 0) { | ||
| // Force going from UNDETERMINED to ACTIVE through BEGAN to preserve the correct state transition flow. | ||
| [self setGestureStateSync:2 forHandler:handlerTag]; |
There was a problem hiding this comment.
| [self setGestureStateSync:2 forHandler:handlerTag]; | |
| handler.recognizer.state = RNGHGestureRecognizerStatePossible; |
Wouldn't this work? I don't see anything else done for the "2" path, so instead of going through the entire flow of finding the gesture and ensuring it's set up correctly twice, we can just change the state directly.
There was a problem hiding this comment.
It would work, but we still need to call handleGesture for begin, I thought that using recursion is cleaner here, but I agree having to find handler again adds unnecessary complexity.
There was a problem hiding this comment.
Pull request overview
Fixes iOS manual gesture activation via GestureStateManager by ensuring the ACTIVE transition doesn’t bypass the expected BEGAN flow, addressing a regression introduced by the recent “fromReset” handling change.
Changes:
- When setting a handler to
ACTIVE, force an initial state progression that triggers the handler’s gesture processing path instead of bypassing it. - Preserve the expected state transition ordering so manually handled gestures can activate correctly.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (handler.recognizer.state == 0) { | ||
| // Force going from UNDETERMINED to ACTIVE through BEGAN to preserve the correct state transition flow. | ||
| handler.recognizer.state = RNGHGestureRecognizerStatePossible; | ||
| [handler handleGesture:handler.recognizer fromReset:NO]; | ||
| } |
There was a problem hiding this comment.
The condition handler.recognizer.state == 0 relies on a magic number (and the comment calls it UNDETERMINED, but 0 corresponds to the platform recognizer “possible” state). This makes the intent unclear and is easy to misread/port incorrectly. Consider comparing against the explicit platform constant (with #if !TARGET_OS_OSX / #else), and update the comment to describe that this branch is about the recognizer being in Possible (used here as a proxy for “no prior BEGAN dispatch”) before forcing a BEGAN dispatch prior to activation.
| } else if (state == 4) { // ACTIVE | ||
| if (handler.recognizer.state == 0) { | ||
| // Force going from UNDETERMINED to ACTIVE through BEGAN to preserve the correct state transition flow. | ||
| handler.recognizer.state = RNGHGestureRecognizerStatePossible; |
There was a problem hiding this comment.
Does setting state here work? As far as I remember, recognizers are quite strict when it comes to setting state and doing so outside onTouches* doesn't work.
There was a problem hiding this comment.
Yeah, it does. This method always relied on setting the state directly.
| } else if (state == 3) { // CANCELLED | ||
| handler.recognizer.state = RNGHGestureRecognizerStateCancelled; | ||
| } else if (state == 4) { // ACTIVE | ||
| if (handler.recognizer.state == 0) { |
There was a problem hiding this comment.
Can we please check for appropriate value from UIGestureRecognizerState?
8849fdd to
caefa77
Compare
Description
The state manager was not functioning correctly on iOS because the state change from begin to activate did not go through begin.
handleStateChangedoesn't callhandleGesturefor activate directly as it bypasses gesture interaction system. Instead it relies on the activate gesture being called from reset.It worked previously, but after commit c6051ca introduced a direct check in
handleGestureto determine whether it was invoked from reset. As a result, manually handled gestures were never activated.Test plan
Tested on the StateManager example.