mirror of
https://github.com/status-im/react-navigation-stack.git
synced 2025-02-22 03:08:05 +00:00
Full gesture flow on horizontal
This commit is contained in:
parent
23ea16e9cf
commit
b8cee7ac7f
@ -19,10 +19,7 @@ import {
|
|||||||
NavigationProvider,
|
NavigationProvider,
|
||||||
} from 'react-navigation';
|
} from 'react-navigation';
|
||||||
import { ScreenContainer } from 'react-native-screens';
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
import {
|
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||||
PanGestureHandler,
|
|
||||||
NativeViewGestureHandler,
|
|
||||||
} from 'react-native-gesture-handler';
|
|
||||||
|
|
||||||
import Card from './StackViewCard';
|
import Card from './StackViewCard';
|
||||||
import Header from '../Header/Header';
|
import Header from '../Header/Header';
|
||||||
@ -277,9 +274,10 @@ class StackViewLayout extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
transitionProps: { scene, scenes },
|
transitionProps: { navigation, scene, scenes },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { options } = scene.descriptor;
|
const { options } = scene.descriptor;
|
||||||
|
const { index } = navigation.state;
|
||||||
|
|
||||||
const gesturesEnabled =
|
const gesturesEnabled =
|
||||||
typeof options.gesturesEnabled === 'boolean'
|
typeof options.gesturesEnabled === 'boolean'
|
||||||
@ -296,7 +294,7 @@ class StackViewLayout extends React.Component {
|
|||||||
// https://github.com/kmagiera/react-native-gesture-handler/issues/293
|
// https://github.com/kmagiera/react-native-gesture-handler/issues/293
|
||||||
return (
|
return (
|
||||||
<PanGestureHandler
|
<PanGestureHandler
|
||||||
minOffsetX={this._isGestureInverted() ? -15 : 15}
|
minOffsetX={this._isMotionInverted() ? -15 : 15}
|
||||||
maxDeltaY={5}
|
maxDeltaY={5}
|
||||||
onGestureEvent={this._handlePanGestureEvent}
|
onGestureEvent={this._handlePanGestureEvent}
|
||||||
onHandlerStateChange={this._handlePanGestureStateChange}
|
onHandlerStateChange={this._handlePanGestureStateChange}
|
||||||
@ -315,17 +313,19 @@ class StackViewLayout extends React.Component {
|
|||||||
// Without using Reanimated it's not possible to do all of the following
|
// Without using Reanimated it's not possible to do all of the following
|
||||||
// stuff with native driver.
|
// stuff with native driver.
|
||||||
_handlePanGestureEvent = ({ nativeEvent }) => {
|
_handlePanGestureEvent = ({ nativeEvent }) => {
|
||||||
const { mode } = this.props;
|
if (this._isMotionVertical()) {
|
||||||
const isVertical = mode === 'modal';
|
|
||||||
|
|
||||||
if (isVertical) {
|
|
||||||
this._handleVerticalPan(nativeEvent);
|
this._handleVerticalPan(nativeEvent);
|
||||||
} else {
|
} else {
|
||||||
this._handleHorizontalPan(nativeEvent);
|
this._handleHorizontalPan(nativeEvent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_isGestureInverted = () => {
|
_isMotionVertical = () => {
|
||||||
|
const { mode } = this.props;
|
||||||
|
return mode === 'modal';
|
||||||
|
};
|
||||||
|
|
||||||
|
_isMotionInverted = () => {
|
||||||
const {
|
const {
|
||||||
transitionProps: { scene },
|
transitionProps: { scene },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -338,22 +338,25 @@ class StackViewLayout extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleHorizontalPan = nativeEvent => {
|
_handleHorizontalPan = nativeEvent => {
|
||||||
|
let value = this._computeHorizontalGestureValue(nativeEvent);
|
||||||
|
console.log({value})
|
||||||
|
this.props.transitionProps.position.setValue(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
_computeHorizontalGestureValue = nativeEvent => {
|
||||||
let {
|
let {
|
||||||
transitionProps: { navigation, position, layout },
|
transitionProps: { navigation, layout },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let { index } = navigation.state;
|
let { index } = navigation.state;
|
||||||
|
|
||||||
let distance = layout.width.__getValue();
|
let distance = layout.width.__getValue();
|
||||||
let translation = nativeEvent.translationX;
|
let translationX = this._isMotionInverted()
|
||||||
|
? -1 * nativeEvent.translationX
|
||||||
|
: nativeEvent.translationX;
|
||||||
|
|
||||||
if (this._isGestureInverted()) {
|
let value = index - translationX / distance;
|
||||||
translation *= -1;
|
console.log({ value, index, translationX })
|
||||||
}
|
return clamp(index - 1, value, index);
|
||||||
|
|
||||||
let currentValue = 1 - translation / distance;
|
|
||||||
let value = clamp(index - 1, currentValue, index);
|
|
||||||
position.setValue(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleVerticalPan = nativeEvent => {
|
_handleVerticalPan = nativeEvent => {
|
||||||
@ -361,8 +364,68 @@ class StackViewLayout extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handlePanGestureStateChange = ({ nativeEvent }) => {
|
_handlePanGestureStateChange = ({ nativeEvent }) => {
|
||||||
const { oldState, state } = nativeEvent;
|
if (nativeEvent.oldState !== State.ACTIVE) {
|
||||||
// console.log({ nativeEvent })
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isMotionVertical()) {
|
||||||
|
this._handleReleaseVertical(nativeEvent);
|
||||||
|
} else {
|
||||||
|
this._handleReleaseHorizontal(nativeEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleReleaseHorizontal = nativeEvent => {
|
||||||
|
const {
|
||||||
|
transitionProps: { navigation, position, layout, scene },
|
||||||
|
mode,
|
||||||
|
} = this.props;
|
||||||
|
const { index } = navigation.state;
|
||||||
|
const immediateIndex =
|
||||||
|
this._immediateIndex == null ? index : this._immediateIndex;
|
||||||
|
|
||||||
|
// Calculate animate duration according to gesture speed and moved distance
|
||||||
|
const distance = layout.width.__getValue();
|
||||||
|
const movementDirection = this._isMotionInverted() ? -1 : 1;
|
||||||
|
const movedDistance = movementDirection * nativeEvent.translationX;
|
||||||
|
const gestureVelocity = movementDirection * nativeEvent.velocityX;
|
||||||
|
const defaultVelocity = distance / ANIMATION_DURATION;
|
||||||
|
const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity);
|
||||||
|
const resetDuration = this._isMotionInverted()
|
||||||
|
? (distance - movedDistance) / velocity
|
||||||
|
: movedDistance / velocity;
|
||||||
|
const goBackDuration = this._isMotionInverted()
|
||||||
|
? movedDistance / velocity
|
||||||
|
: (distance - movedDistance) / velocity;
|
||||||
|
|
||||||
|
let value = this._computeHorizontalGestureValue(nativeEvent);
|
||||||
|
|
||||||
|
// If the speed of the gesture release is significant, use that as the indication
|
||||||
|
// of intent
|
||||||
|
if (gestureVelocity < -0.5) {
|
||||||
|
this.props.onGestureCanceled && this.props.onGestureCanceled();
|
||||||
|
this._reset(immediateIndex, resetDuration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gestureVelocity > 0.5) {
|
||||||
|
this.props.onGestureFinish && this.props.onGestureFinish();
|
||||||
|
this._goBack(immediateIndex, goBackDuration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then filter based on the distance the screen was moved. Over a third of the way swiped,
|
||||||
|
// and the back will happen.
|
||||||
|
if (value <= index - POSITION_THRESHOLD) {
|
||||||
|
this.props.onGestureFinish && this.props.onGestureFinish();
|
||||||
|
this._goBack(immediateIndex, goBackDuration);
|
||||||
|
} else {
|
||||||
|
this.props.onGestureCanceled && this.props.onGestureCanceled();
|
||||||
|
this._reset(immediateIndex, resetDuration);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleReleaseVertical = nativeEvent => {
|
||||||
|
// todo
|
||||||
};
|
};
|
||||||
|
|
||||||
_getHeaderMode() {
|
_getHeaderMode() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user