diff --git a/example/rn-cli.config.js b/example/rn-cli.config.js index c049b59..faa16fe 100644 --- a/example/rn-cli.config.js +++ b/example/rn-cli.config.js @@ -4,8 +4,10 @@ const path = require('path'); const glob = require('glob-to-regexp'); const blacklist = require('metro/src/blacklist'); const pak = require('../package.json'); +const pak2 = require('./package.json'); const dependencies = Object.keys(pak.dependencies); +const localDependencies = Object.keys(pak2.dependencies); const peerDependencies = Object.keys(pak.peerDependencies); module.exports = { @@ -13,7 +15,7 @@ module.exports = { return [__dirname, path.resolve(__dirname, '..')]; }, getProvidesModuleNodeModules() { - return [...dependencies, ...peerDependencies]; + return [...dependencies, ...localDependencies, ...peerDependencies]; }, getBlacklistRE() { return blacklist([glob(`${path.resolve(__dirname, '..')}/node_modules/*`)]); diff --git a/package.json b/package.json index a7ced87..4a2e7b5 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "test": "jest", "lint": "eslint .", "format": "eslint . --fix", - "precommit": "yarn lint && yarn test", "build": "babel --no-babelrc --plugins=syntax-jsx,syntax-class-properties,syntax-object-rest-spread,transform-flow-strip-types src --copy-files --out-dir dist --ignore '**/__tests__/**'", "prepare": "yarn build" }, @@ -58,6 +57,8 @@ "react": "*", "react-native": "*", "react-native-screens": "^1.0.0 || ^1.0.0-alpha", + "react-native-gesture-handler": "^1.0.0", + "react-native-reanimated": "^1.0.0 || ^1.0.0-alpha", "react-navigation": ">=2.0 || ^2.0.0-beta" }, "jest": { diff --git a/src/views/Header/Header.js b/src/views/Header/Header.js index 189b711..e93dc79 100644 --- a/src/views/Header/Header.js +++ b/src/views/Header/Header.js @@ -523,7 +523,6 @@ class Header extends React.PureComponent { }); const scenesProps = Object.values(scenesByIndex).map(scene => ({ position: this.props.position, - progress: this.props.progress, scene, })); appBar = scenesProps.map(this._renderHeader, this); @@ -531,7 +530,6 @@ class Header extends React.PureComponent { } else { const headerProps = { position: new Animated.Value(this.props.scene.index), - progress: new Animated.Value(0), scene: this.props.scene, }; diff --git a/src/views/StackView/StackViewLayout.js b/src/views/StackView/StackViewLayout.js index 6838d4a..77ea95f 100644 --- a/src/views/StackView/StackViewLayout.js +++ b/src/views/StackView/StackViewLayout.js @@ -19,6 +19,7 @@ import { NavigationProvider, } from 'react-navigation'; import { ScreenContainer } from 'react-native-screens'; +import { PanGestureHandler } from 'react-native-gesture-handler'; import Card from './StackViewCard'; import Header from '../Header/Header'; @@ -252,188 +253,6 @@ class StackViewLayout extends React.Component { } } - _panResponder = PanResponder.create({ - onPanResponderTerminate: () => { - const { navigation } = this.props.transitionProps; - const { index } = navigation.state; - this._isResponding = false; - this._reset(index, 0); - this.props.onGestureCanceled && this.props.onGestureCanceled(); - }, - onPanResponderGrant: () => { - const { - transitionProps: { navigation, position, scene }, - } = this.props; - const { index } = navigation.state; - - if (index !== scene.index) { - return false; - } - - position.stopAnimation(value => { - this._isResponding = true; - this._gestureStartValue = value; - }); - this.props.onGestureBegin && this.props.onGestureBegin(); - }, - onMoveShouldSetPanResponder: (event, gesture) => { - const { - transitionProps: { navigation, layout, scene }, - mode, - } = this.props; - const { index } = navigation.state; - const isVertical = mode === 'modal'; - const { options } = scene.descriptor; - const gestureDirection = options.gestureDirection; - - const gestureDirectionInverted = - typeof gestureDirection === 'string' - ? gestureDirection === 'inverted' - : I18nManager.isRTL; - - if (index !== scene.index) { - return false; - } - - const immediateIndex = - this._immediateIndex == null ? index : this._immediateIndex; - const currentDragDistance = gesture[isVertical ? 'dy' : 'dx']; - const currentDragPosition = - event.nativeEvent[isVertical ? 'pageY' : 'pageX']; - const axisLength = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const axisHasBeenMeasured = !!axisLength; - - // Measure the distance from the touch to the edge of the screen - const screenEdgeDistance = gestureDirectionInverted - ? axisLength - (currentDragPosition - currentDragDistance) - : currentDragPosition - currentDragDistance; - // Compare to the gesture distance relavant to card or modal - - const { - gestureResponseDistance: userGestureResponseDistance = {}, - } = options; - const gestureResponseDistance = isVertical - ? userGestureResponseDistance.vertical || - GESTURE_RESPONSE_DISTANCE_VERTICAL - : userGestureResponseDistance.horizontal || - GESTURE_RESPONSE_DISTANCE_HORIZONTAL; - // GESTURE_RESPONSE_DISTANCE is about 25 or 30. Or 135 for modals - if (screenEdgeDistance > gestureResponseDistance) { - // Reject touches that started in the middle of the screen - return false; - } - - const hasDraggedEnough = - Math.abs(currentDragDistance) > RESPOND_THRESHOLD; - - const isOnFirstCard = immediateIndex === 0; - const shouldSetResponder = - hasDraggedEnough && axisHasBeenMeasured && !isOnFirstCard; - return shouldSetResponder; - }, - onPanResponderMove: (event, gesture) => { - const { - transitionProps: { navigation, position, layout, scene }, - mode, - } = this.props; - const { index } = navigation.state; - const isVertical = mode === 'modal'; - const { options } = scene.descriptor; - const gestureDirection = options.gestureDirection; - - const gestureDirectionInverted = - typeof gestureDirection === 'string' - ? gestureDirection === 'inverted' - : I18nManager.isRTL; - - // Handle the moving touches for our granted responder - const startValue = this._gestureStartValue; - const axis = isVertical ? 'dy' : 'dx'; - const axisDistance = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const currentValue = - axis === 'dx' && gestureDirectionInverted - ? startValue + gesture[axis] / axisDistance - : startValue - gesture[axis] / axisDistance; - const value = clamp(index - 1, currentValue, index); - position.setValue(value); - }, - onPanResponderTerminationRequest: () => - // Returning false will prevent other views from becoming responder while - // the navigation view is the responder (mid-gesture) - false, - onPanResponderRelease: (event, gesture) => { - const { - transitionProps: { navigation, position, layout, scene }, - mode, - } = this.props; - const { index } = navigation.state; - const isVertical = mode === 'modal'; - const { options } = scene.descriptor; - const gestureDirection = options.gestureDirection; - - const gestureDirectionInverted = - typeof gestureDirection === 'string' - ? gestureDirection === 'inverted' - : I18nManager.isRTL; - - if (!this._isResponding) { - return; - } - this._isResponding = false; - - const immediateIndex = - this._immediateIndex == null ? index : this._immediateIndex; - - // Calculate animate duration according to gesture speed and moved distance - const axisDistance = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const movementDirection = gestureDirectionInverted ? -1 : 1; - const movedDistance = - movementDirection * gesture[isVertical ? 'dy' : 'dx']; - const gestureVelocity = - movementDirection * gesture[isVertical ? 'vy' : 'vx']; - const defaultVelocity = axisDistance / ANIMATION_DURATION; - const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity); - const resetDuration = gestureDirectionInverted - ? (axisDistance - movedDistance) / velocity - : movedDistance / velocity; - const goBackDuration = gestureDirectionInverted - ? movedDistance / velocity - : (axisDistance - movedDistance) / velocity; - - // To asyncronously get the current animated value, we need to run stopAnimation: - position.stopAnimation(value => { - // 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); - } - }); - }, - }); - _onFloatingHeaderLayout = e => { this.setState({ floatingHeaderHeight: e.nativeEvent.layout.height }); }; @@ -464,24 +283,62 @@ class StackViewLayout extends React.Component { ? options.gesturesEnabled : Platform.OS === 'ios'; - const responder = !gesturesEnabled ? null : this._panResponder; - - const handlers = gesturesEnabled ? responder.panHandlers : {}; const containerStyle = [ styles.container, this._getTransitionConfig().containerStyle, ]; return ( - - - {scenes.map(s => this._renderCard(s))} - - {floatingHeader} - + + + + {scenes.map(s => this._renderCard(s))} + + {floatingHeader} + + ); } + _handlePanGestureEvent = ({ nativeEvent }) => { + // const startValue = this._gestureStartValue; + // const axis = isVertical ? 'dy' : 'dx'; + // const axisDistance = isVertical + // ? layout.height.__getValue() + // : layout.width.__getValue(); + // const currentValue = + // axis === 'dx' && gestureDirectionInverted + // ? startValue + gesture[axis] / axisDistance + // : startValue - gesture[axis] / axisDistance; + // const value = clamp(index - 1, currentValue, index); + // position.setValue(value); + + + // Without using Reanimated it's not possible to do all of the following + // stuff with native driver. + const { + transitionProps: { navigation, position, layout, scene }, + mode, + } = this.props; + const { index } = navigation.state; + const distance = layout.width.__getValue(); + const translation = nativeEvent.translationX; + const currentValue = 1 - translation / distance; + const value = clamp(index - 1, currentValue, index); + console.log({ distance, translation, currentValue }) + position.setValue(value); + } + + _handlePanGestureStateChange = ({ nativeEvent }) => { + const { oldState, state } = nativeEvent; + // console.log({ nativeEvent }) + } + _getHeaderMode() { if (this.props.headerMode) { return this.props.headerMode; diff --git a/src/views/Transitioner.js b/src/views/Transitioner.js index 9437215..3bbfc0c 100644 --- a/src/views/Transitioner.js +++ b/src/views/Transitioner.js @@ -28,7 +28,6 @@ class Transitioner extends React.Component { this.state = { layout, position: new Animated.Value(this.props.navigation.state.index), - progress: new Animated.Value(1), scenes: NavigationScenesReducer( [], this.props.navigation.state, @@ -90,9 +89,7 @@ class Transitioner extends React.Component { scenes: nextScenes, }; - const { position, progress } = nextState; - - progress.setValue(0); + const { position } = nextState; this._prevTransitionProps = this._transitionProps; this._transitionProps = buildTransitionProps(nextProps, nextState); @@ -108,7 +105,6 @@ class Transitioner extends React.Component { if (result instanceof Promise) { await result; } - progress.setValue(1); position.setValue(toValue); this._onTransitionEnd(); }); @@ -137,10 +133,6 @@ class Transitioner extends React.Component { const animations = indexHasChanged && positionHasChanged ? [ - timing(progress, { - ...transitionSpec, - toValue: 1, - }), timing(position, { ...transitionSpec, toValue: nextProps.navigation.state.index, @@ -245,7 +237,7 @@ class Transitioner extends React.Component { function buildTransitionProps(props, state) { const { navigation } = props; - const { layout, position, progress, scenes } = state; + const { layout, position, scenes } = state; const scene = scenes.find(isSceneActive); @@ -255,7 +247,6 @@ function buildTransitionProps(props, state) { layout, navigation, position, - progress, scenes, scene, index: scene.index,