Skip to content

Commit

Permalink
chore: add onGestureCancel event (#1810)
Browse files Browse the repository at this point in the history
## Description

This PR adds new iOS only event. Event is triggered after canceled swipe
back (as on video)


https://github.com/software-mansion/react-native-screens/assets/36106620/e9f63c7c-e6b4-4444-895a-d6b41c725963
  • Loading branch information
piaskowyk authored Jul 12, 2023
1 parent 015809b commit 990e6ef
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 0 deletions.
1 change: 1 addition & 0 deletions ios/RNSScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy) RCTDirectEventBlock onWillDisappear;
@property (nonatomic, copy) RCTDirectEventBlock onNativeDismissCancelled;
@property (nonatomic, copy) RCTDirectEventBlock onTransitionProgress;
@property (nonatomic, copy) RCTDirectEventBlock onGestureCancel;
#endif // RCT_NEW_ARCH_ENABLED

- (void)notifyFinishTransitioning;
Expand Down
17 changes: 17 additions & 0 deletions ios/RNSScreen.mm
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ - (void)notifyDisappear
#endif
}

- (void)notifyGestureCancel
{
#ifdef RCT_NEW_ARCH_ENABLED
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNSScreenEventEmitter>(_eventEmitter)
->onGestureCancel(facebook::react::RNSScreenEventEmitter::OnGestureCancel{});
}
#else
if (self.onGestureCancel) {
self.onGestureCancel(nil);
}
#endif
}

- (BOOL)isMountedUnderScreenOrReactRoot
{
#ifdef RCT_NEW_ARCH_ENABLED
Expand Down Expand Up @@ -886,6 +900,8 @@ - (void)viewDidAppear:(BOOL)animated
// or successfully swiped back
[self.screenView notifyAppear];
[self notifyTransitionProgress:1.0 closing:NO goingForward:_goingForward];
} else {
[self.screenView notifyGestureCancel];
}

_isSwiping = NO;
Expand Down Expand Up @@ -1275,6 +1291,7 @@ @implementation RNSScreenManager
RCT_EXPORT_VIEW_PROPERTY(onTransitionProgress, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onWillAppear, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onWillDisappear, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGestureCancel, RCTDirectEventBlock);

#if !TARGET_OS_TV
RCT_EXPORT_VIEW_PROPERTY(screenOrientation, UIInterfaceOrientationMask)
Expand Down
1 change: 1 addition & 0 deletions src/fabric/ScreenNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface NativeProps extends ViewProps {
onWillAppear?: BubblingEventHandler<ScreenEvent>;
onWillDisappear?: BubblingEventHandler<ScreenEvent>;
onTransitionProgress?: BubblingEventHandler<TransitionProgressEvent>;
onGestureCancel?: BubblingEventHandler<ScreenEvent>;
sheetAllowedDetents?: WithDefault<SheetDetentTypes, 'large'>;
sheetLargestUndimmedDetent?: WithDefault<SheetDetentTypes, 'all'>;
sheetGrabberVisible?: WithDefault<boolean, false>;
Expand Down
7 changes: 7 additions & 0 deletions src/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ class InnerScreen extends React.Component<ScreenProps> {
children,
isNativeStack,
gestureResponseDistance,
onGestureCancel,
...props
} = rest;

Expand Down Expand Up @@ -340,6 +341,12 @@ class InnerScreen extends React.Component<ScreenProps> {
{ useNativeDriver: true }
)
}
onGestureCancel={
onGestureCancel ??
(() => {
// for internal use
})
}
>
{!isNativeStack ? ( // see comment of this prop in types.tsx for information why it is needed
children
Expand Down
4 changes: 4 additions & 0 deletions src/native-stack/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export type NativeStackNavigationEventMap = {
* Event which fires when a transition animation ends.
*/
transitionEnd: { data: { closing: boolean } };
/**
* Event which fires when a swipe back is canceled on iOS.
*/
gestureCancel: { data: undefined };
};

export type NativeStackNavigationProp<
Expand Down
6 changes: 6 additions & 0 deletions src/native-stack/views/NativeStackView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ const RouteView = ({
target: stateKey,
});
}}
onGestureCancel={() => {
navigation.emit({
type: 'gestureCancel',
target: route.key,
});
}}
>
<HeaderHeightContext.Provider
value={
Expand Down
4 changes: 4 additions & 0 deletions src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ export interface ScreenProps extends ViewProps {
* The callback takes the number of dismissed screens as an argument since iOS 14 native header back button can pop more than 1 screen at a time.
*/
onDismissed?: (e: NativeSyntheticEvent<{ dismissCount: number }>) => void;
/**
* A callback that gets called after swipe back is canceled.
*/
onGestureCancel?: (e: NativeSyntheticEvent<null>) => void;
/**
* An internal callback that gets called when the native header back button is clicked on Android and `enableNativeBackButtonDismissal` is set to `false`. It dismises the screen using `navigation.pop()`.
*
Expand Down

0 comments on commit 990e6ef

Please sign in to comment.