mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-12 22:51:18 +08:00
fix: dispatch pop early when screen is closed with gesture (#336)
fixes #267
This commit is contained in:
2
.github/workflows/expo-preview.yml
vendored
2
.github/workflows/expo-preview.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
node-version: 10.x
|
||||
|
||||
- name: Setup Expo
|
||||
uses: expo/expo-github-action@v5
|
||||
|
||||
@@ -286,7 +286,7 @@ export default function App() {
|
||||
<List.Item
|
||||
key={name}
|
||||
title={SCREENS[name].title}
|
||||
onPress={() => navigation.push(name)}
|
||||
onPress={() => navigation.navigate(name)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
Route,
|
||||
ParamListBase,
|
||||
} from '@react-navigation/native';
|
||||
import { StackNavigationState } from '@react-navigation/routers';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import Header from './Header';
|
||||
@@ -28,10 +27,10 @@ export type Props = {
|
||||
layout: Layout;
|
||||
insets: EdgeInsets;
|
||||
scenes: (Scene<Route<string>> | undefined)[];
|
||||
state: StackNavigationState;
|
||||
getPreviousRoute: (props: {
|
||||
route: Route<string>;
|
||||
}) => Route<string> | undefined;
|
||||
getFocusedRoute: () => Route<string>;
|
||||
onContentHeightChange?: (props: {
|
||||
route: Route<string>;
|
||||
height: number;
|
||||
@@ -46,14 +45,14 @@ export default function HeaderContainer({
|
||||
scenes,
|
||||
layout,
|
||||
insets,
|
||||
state,
|
||||
getFocusedRoute,
|
||||
getPreviousRoute,
|
||||
onContentHeightChange,
|
||||
gestureDirection,
|
||||
styleInterpolator,
|
||||
style,
|
||||
}: Props) {
|
||||
const focusedRoute = state.routes[state.index];
|
||||
const focusedRoute = getFocusedRoute();
|
||||
|
||||
return (
|
||||
<View pointerEvents="box-none" style={style}>
|
||||
|
||||
@@ -133,6 +133,8 @@ export default class Card extends React.Component<Props> {
|
||||
|
||||
private interactionHandle: number | undefined;
|
||||
|
||||
private pendingGestureCallback: number | undefined;
|
||||
|
||||
private animate = ({
|
||||
closing,
|
||||
velocity,
|
||||
@@ -161,6 +163,8 @@ export default class Card extends React.Component<Props> {
|
||||
this.setPointerEventsEnabled(!closing);
|
||||
this.handleStartInteraction();
|
||||
|
||||
clearTimeout(this.pendingGestureCallback);
|
||||
|
||||
onTransitionStart?.({ closing });
|
||||
animation(gesture, {
|
||||
...spec.config,
|
||||
@@ -171,6 +175,8 @@ export default class Card extends React.Component<Props> {
|
||||
}).start(({ finished }) => {
|
||||
this.handleEndInteraction();
|
||||
|
||||
clearTimeout(this.pendingGestureCallback);
|
||||
|
||||
if (finished) {
|
||||
if (closing) {
|
||||
onClose();
|
||||
@@ -221,6 +227,7 @@ export default class Card extends React.Component<Props> {
|
||||
}: PanGestureHandlerGestureEvent) => {
|
||||
const {
|
||||
layout,
|
||||
onClose,
|
||||
onGestureBegin,
|
||||
onGestureCanceled,
|
||||
onGestureEnd,
|
||||
@@ -266,6 +273,16 @@ export default class Card extends React.Component<Props> {
|
||||
: false;
|
||||
|
||||
this.animate({ closing, velocity });
|
||||
|
||||
if (closing) {
|
||||
// We call onClose with a delay to make sure that the animation has already started
|
||||
// This will make sure that the state update caused by this doesn't affect start of animation
|
||||
this.pendingGestureCallback = (setTimeout(
|
||||
onClose,
|
||||
32
|
||||
) as any) as number;
|
||||
}
|
||||
|
||||
onGestureEnd?.();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
ViewStyle,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import { StackNavigationState } from '@react-navigation/routers';
|
||||
import { Route, useTheme } from '@react-navigation/native';
|
||||
import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
|
||||
import Card from './Card';
|
||||
@@ -23,7 +22,6 @@ type Props = TransitionPreset & {
|
||||
gesture: Animated.Value;
|
||||
previousScene?: Scene<Route<string>>;
|
||||
scene: Scene<Route<string>>;
|
||||
state: StackNavigationState;
|
||||
safeAreaInsetTop: number;
|
||||
safeAreaInsetRight: number;
|
||||
safeAreaInsetBottom: number;
|
||||
@@ -34,6 +32,7 @@ type Props = TransitionPreset & {
|
||||
getPreviousRoute: (props: {
|
||||
route: Route<string>;
|
||||
}) => Route<string> | undefined;
|
||||
getFocusedRoute: () => Route<string>;
|
||||
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
||||
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
||||
onOpenRoute: (props: { route: Route<string> }) => void;
|
||||
@@ -78,6 +77,7 @@ function CardContainer({
|
||||
gestureResponseDistance,
|
||||
gestureVelocityImpact,
|
||||
getPreviousRoute,
|
||||
getFocusedRoute,
|
||||
headerMode,
|
||||
headerShown,
|
||||
headerStyleInterpolator,
|
||||
@@ -101,7 +101,6 @@ function CardContainer({
|
||||
safeAreaInsetRight,
|
||||
safeAreaInsetTop,
|
||||
scene,
|
||||
state,
|
||||
transitionSpec,
|
||||
}: Props) {
|
||||
React.useEffect(() => {
|
||||
@@ -203,8 +202,8 @@ function CardContainer({
|
||||
layout,
|
||||
insets,
|
||||
scenes: [previousScene, scene],
|
||||
state,
|
||||
getPreviousRoute,
|
||||
getFocusedRoute,
|
||||
gestureDirection,
|
||||
styleInterpolator: headerStyleInterpolator,
|
||||
onContentHeightChange: onHeaderHeightChange,
|
||||
|
||||
@@ -398,6 +398,12 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
private getFocusedRoute = () => {
|
||||
const { state } = this.props;
|
||||
|
||||
return state.routes[state.index];
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
mode,
|
||||
@@ -581,7 +587,6 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
gesture={gesture}
|
||||
scene={scene}
|
||||
previousScene={previousScene}
|
||||
state={state}
|
||||
safeAreaInsetTop={safeAreaInsetTop}
|
||||
safeAreaInsetRight={safeAreaInsetRight}
|
||||
safeAreaInsetBottom={safeAreaInsetBottom}
|
||||
@@ -596,6 +601,7 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
headerHeight={headerHeights[route.key]}
|
||||
onHeaderHeightChange={this.handleHeaderLayout}
|
||||
getPreviousRoute={getPreviousRoute}
|
||||
getFocusedRoute={this.getFocusedRoute}
|
||||
headerMode={headerMode}
|
||||
headerShown={headerShown}
|
||||
headerTransparent={headerTransparent}
|
||||
@@ -619,8 +625,8 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
layout,
|
||||
insets: { top, right, bottom, left },
|
||||
scenes,
|
||||
state,
|
||||
getPreviousRoute,
|
||||
getFocusedRoute: this.getFocusedRoute,
|
||||
onContentHeightChange: this.handleHeaderLayout,
|
||||
gestureDirection:
|
||||
focusedOptions.gestureDirection !== undefined
|
||||
|
||||
@@ -314,14 +314,18 @@ class StackView extends React.Component<Props, State> {
|
||||
source: route.key,
|
||||
target: state.key,
|
||||
});
|
||||
} else {
|
||||
// We need to clean up any state tracking the route and pop it immediately
|
||||
this.setState(state => ({
|
||||
routes: state.routes.filter(r => r.key !== route.key),
|
||||
openingRouteKeys: state.openingRouteKeys.filter(
|
||||
key => key !== route.key
|
||||
),
|
||||
closingRouteKeys: state.closingRouteKeys.filter(
|
||||
key => key !== route.key
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
// We need to clean up any state tracking the route and pop it immediately
|
||||
this.setState(state => ({
|
||||
routes: state.routes.filter(r => r.key !== route.key),
|
||||
openingRouteKeys: state.openingRouteKeys.filter(key => key !== route.key),
|
||||
closingRouteKeys: state.closingRouteKeys.filter(key => key !== route.key),
|
||||
}));
|
||||
};
|
||||
|
||||
private handleTransitionStart = (
|
||||
|
||||
Reference in New Issue
Block a user