Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/424.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应导航:使用NavigationActions.reset、goBack和getStateForAction导航回根目录_Javascript_Reactjs_React Native_React Navigation - Fatal编程技术网

Javascript 反应导航:使用NavigationActions.reset、goBack和getStateForAction导航回根目录

Javascript 反应导航:使用NavigationActions.reset、goBack和getStateForAction导航回根目录,javascript,reactjs,react-native,react-navigation,Javascript,Reactjs,React Native,React Navigation,假设我在StackNavigator应用程序中浏览了4个屏幕,现在我想返回到第一个屏幕。似乎有三种不同的方法可以做到这一点,它们确实可以导航到我想做的地方,但是每种方法都有一个动画循环通过前面的每个屏幕 是否有一种从SCREEN\u D导航到SCREEN\u a的干净方法 换句话说,当从SCREEN\u D navigation.navigate(SCREEN_A); ... navigation.navigate(SCREEN_B); ... navigation.navigate(SCREE

假设我在StackNavigator应用程序中浏览了4个屏幕,现在我想返回到第一个屏幕。似乎有三种不同的方法可以做到这一点,它们确实可以导航到我想做的地方,但是每种方法都有一个动画循环通过前面的每个屏幕

是否有一种从
SCREEN\u D
导航到
SCREEN\u a
的干净方法

换句话说,当从
SCREEN\u D

navigation.navigate(SCREEN_A);
...
navigation.navigate(SCREEN_B);
...
navigation.navigate(SCREEN_C);
...
navigation.navigate(SCREEN_D);
有三种方法可以做到这一点:

一,

二,

三,

这里有一个快速解决方案。 这将在导航(向前或向后)时删除所有转换

在transitionConfig中添加以下内容:

const transitionConfig = () => ({
    transitionSpec: {
      duration: 0,
      timing: Animated.timing,
      easing: Easing.step0,
    },
  })
transitionConfig是一个返回覆盖默认屏幕转换的对象的函数

  • 如果有人知道一种在单一导航上改变动画的方法,我很想知道怎么做
我也花了一些时间在这方面,让我总结一下我的发现,有多种解决方案/解决方法:

1) 使用
CardStackStyleInterpolator
所提到的问题似乎被合并了。因此,您可以通过此导入加载
CardStackStyleInterpolator

import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator'
要这样应用它:

const YourStackNavigator = StackNavigator({
    Screen1: { screen: Screen1 },
    Screen2: { screen: Screen2 },
}, {
    transitionConfig: () => ({
        screenInterpolator: (props) => CardStackStyleInterpolator.forHorizontal(props)
    })
});
在我的例子中,我只是跳转到下一个屏幕,如下所示:

this.props.navigation.navigate('Modal_AddGoodClass');
但在我的reducer中,我在触发
Modal_AddGoodClass
屏幕时重置了导航器:

const NewExportReceiptNavigationReducer = (state, action) => {
    // Default stuff

    let newStateBuffer = newState || state;

    if (action) {
        if (action.type === 'Navigation/NAVIGATE') {
            if (action.routeName === 'Modal_AddGoodClass') {
                newStateBuffer = {
                    index:  0,
                    routes: [
                        newStateBuffer.routes[newStateBuffer.routes.length - 1]
                    ]
                };
            }
        }
    }

    return newStateBuffer;
};

module.exports = NewExportReceiptNavigationReducer;
这非常有效,除了使用“后退”动画而不是“前进”动画之外

您还可以找到一些使用
CardStackStyleInterpolator
的示例代码

2) 覆盖
getStateForAction
: 如上所述,您可以覆盖路由器的
getStateForAction
,以避免导航器返回。除了iOS上的“刷回”手势外,这似乎还起作用:

Nav = StackNavigator(navScreens, navOptions);
const defaultGetStateForAction = Nav.router.getStateForAction;
Nav.router.getStateForAction = (action, state) => {
  if (
    state &&
    action.type === NavigationActions.BACK &&
    (
      state.routes[state.index].routeName === 'Login' ||
      state.routes[state.index].routeName === 'Main'
    )
  ) {
    // Returning null indicates stack end, and triggers exit
    return null;
  }
  return defaultGetStateForAction(action, state);
};

这是我的工作解决方案,用于在不创建新路由的情况下重置回主(根目录)

if(this.categoriesNav.state.nav.index >0){
    let k = this.categoriesNav.state.nav.routes[1].key;
    this.categoriesNav.dispatch(NavigationActions.back({key: k})); }

categoriesNav
引用到我的堆栈导航器

您可以使用。此外,如果您使用的是redux,则应该更新您的


希望这有帮助

react导航有
poptoop
,我们可以像blow一样使用它

this.props.navigation.popToTop()

我想我找到了一个本文中描述的解决方案,它解释了导航是如何工作的(我强烈建议阅读它,因为它是一个非常快速的阅读,并帮助我更好地理解转换是如何工作的)

下面是一个示例导航器的gif,该导航器具有用于来回移动多个屏幕的平滑过渡: (对不起,这是一个链接,我没有足够的代表还嵌入视频,所以我必须做一个链接)。但是,这显示了源代码如下的导航器的行为

基本上,如果您想从堆栈上的屏幕4转到1,您可以将不透明度2和3设置为0,这样过渡将显示为从4转到1

以下是导航器的源代码:

import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ScreenA from './ScreenA';
import ScreenB from './ScreenB';
import ScreenC from './ScreenC';
import ScreenD from './ScreenD';

const OuterNavigator = createStackNavigator(
{
    ScreenA: {
        screen: ScreenA,
        navigationOptions: {
            //Set header stuff here
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#4444aa',
            },
            headerTitle: "Screen A"
        }
    },
    ScreenB: {
        screen: ScreenB,
        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#44aa44',
            },
            headerTitle: "Screen B"
        }
    },
    ScreenC: {
        screen: ScreenC,

        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#aa4444',
            },
            headerTitle: "Screen C"
        }
    },
    ScreenD: {
        screen: ScreenD,

        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#44aaaa',
            },
            headerTitle: "Screen D"
        }
    },
},

{
    // Sets initial screen to screen A
    initialRouteName: 'ScreenA',

    // Can be changed to whatever you prefer
    headerMode: 'float',

    // This line makes a transparent background so the navigator can be wrapped in a background image
    // (this was an issue I struggled with and figured there's a change someone else might be as well)
    cardStyle: { backgroundColor: '00000000', shadowColor: '000000' },
    transitionConfig: () => ({
        // This link exlpains this in detail: 
        // https://medium.com/async-la/custom-transitions-in-react-navigation-2f759408a053
        containerStyle: {
            // This also has to do with having a background image
            backgroundColor: '00000000',
        },
        transitionSpec: {
            // Sets speed for transition (lower -> faster)
            duration: 500,
            useNativeDriver: true,
        },
        screenInterpolator: sceneProps => {
            // Parses scene props
            const { position, layout, scene, index, scenes } = sceneProps

            // Grabs height and width of screen
            const toIndex = index
            const thisSceneIndex = scene.index
            const height = layout.initHeight
            const width = layout.initWidth

            // Grab index of last screen
            const lastSceneIndex = scenes[scenes.length - 1].index

            // Calculates change in indices
            const deltaScene = (lastSceneIndex - toIndex == 0) ? 1 : (lastSceneIndex - toIndex);

            let translateX = position.interpolate({
                inputRange: [thisSceneIndex - 1, thisSceneIndex],
                // Adjusts how the output get scaled
                outputRange: [width / deltaScene, 0],
            });

            const translateY = position.interpolate({
                // Not used, but in the link they use this for vertical transitions
                // If you're interested in that this would do it
                inputRange: [0, thisSceneIndex],
                outputRange: [height, 0]
            });

            // MAGIC HAPPENS HERE:
            // Test whether we're skipping back more than one screen
            // and slide from bottom if true
            if (lastSceneIndex - toIndex > 1) {
                // If you want the screen to which you are transitioning to not move
                // have return; in this if block (see link). If you want behaviour as 
                // shown in the GIF then leave this
                if (scene.index === toIndex) {
                    return { transform: [{ translateX }] }
                }
                // BIG MAGIC HERE
                // Hide all screens in between
                if (scene.index !== lastSceneIndex) return { opacity: 0 }

            }
            return { transform: [{ translateX }] }
        },
    }),
}
);
例如,假设堆栈类似于[A,B,C,D](因此D位于顶部)。lastSceneIndex获取最后一个场景的索引(在本例中为D)。DeltaScene计算场景的变化量。DeltaScene只会是!=1当一个返回到多个屏幕时。如果您不熟悉translateX的工作原理,我强烈建议您阅读上述链接;输出范围为[width/deltaScene,0]的原因是在动画开始之前,屏幕堆叠在一起,然后动画比例将像[A][B][C][D]一样展开,其中每个屏幕都是宽度/deltaScene。在这个例子中,deltaScene是3,所以B是A右边的宽度/3,C是A右边的2*width/3,D是A右边的3*width/3=宽度,这就是我们想要的。如果没有deltaScene,D向右飞的速度比A在屏幕上的速度快3倍,这会造成一个丑陋的过渡

此外,我怀疑是否有人需要看到这一点,但为了以防万一,这里介绍了它在App.js中的使用方式(提供程序用于redux,因此,如果您不想处理这一问题,可能可以省略)


...
const styles=StyleSheet.create({
背景图片:{
弹性:1,
}
});
我真的希望这有帮助!
我还是一个新手,不会做出土生土长的反应,所以如果我犯了任何错误,或者有进一步改进或解释的余地,请在评论中对我/任何其他可能看到这一点的人说出来

对于2020/react导航堆栈,我在设置StackNavigator时使用以下代码:

import { createStackNavigator, CardStyleInterpolators } from 'react-navigation-stack';
import { Easing } from 'react-native';

const Navigator = createStackNavigator({
  // ...
}, {
  defaultNavigationOptions: ({ navigation }) => {
    const animation = navigation.getParam('_animation');
    return {
      // ...
      cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
      ...(animation === 'back' && {
        gestureDirection: 'horizontal-inverted',
      }),
      ...(animation === 'skip' && {
        transitionSpec: {
          open: { animation: 'timing', config: { duration: 0, easing: Easing.step1 }, },
          close: { animation: 'timing', config: { duration: 0, easing: Easing.step0 }, },
        },
      }),
    };
  },
});

和_animation参数以覆盖动画样式

// replace to a route not in the stack normally creates a forward animation, but
// we want a backwards animation
this.props.navigation.dispatch(
  StackActions.replace({ routeName: 'Login', params: { _animation: 'back' } })
);

您是否尝试过Navigator.Disclose()?我在文件里没看到。你有链接吗@这里有一个请求:@CristianoSantos真棒!这是我最好的答案!非常感谢!这会从堆栈中卸载所有屏幕吗?根据官方消息:
它跳回堆栈中的顶部路径,忽略所有其他屏幕
,感谢您的提示。我做了更简单的版本:
defaultNavigationOptions:({navigation})=>{
..
const skipAnimation=navigation.getParam('skipAnimation')??false
..
animationEnabled:!skipAnimation,
。请参阅
this.props.navigation.popToTop()
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ScreenA from './ScreenA';
import ScreenB from './ScreenB';
import ScreenC from './ScreenC';
import ScreenD from './ScreenD';

const OuterNavigator = createStackNavigator(
{
    ScreenA: {
        screen: ScreenA,
        navigationOptions: {
            //Set header stuff here
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#4444aa',
            },
            headerTitle: "Screen A"
        }
    },
    ScreenB: {
        screen: ScreenB,
        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#44aa44',
            },
            headerTitle: "Screen B"
        }
    },
    ScreenC: {
        screen: ScreenC,

        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#aa4444',
            },
            headerTitle: "Screen C"
        }
    },
    ScreenD: {
        screen: ScreenD,

        navigationOptions: {
            headerTintColor: "#fff",
            headerStyle: {
                backgroundColor: '#44aaaa',
            },
            headerTitle: "Screen D"
        }
    },
},

{
    // Sets initial screen to screen A
    initialRouteName: 'ScreenA',

    // Can be changed to whatever you prefer
    headerMode: 'float',

    // This line makes a transparent background so the navigator can be wrapped in a background image
    // (this was an issue I struggled with and figured there's a change someone else might be as well)
    cardStyle: { backgroundColor: '00000000', shadowColor: '000000' },
    transitionConfig: () => ({
        // This link exlpains this in detail: 
        // https://medium.com/async-la/custom-transitions-in-react-navigation-2f759408a053
        containerStyle: {
            // This also has to do with having a background image
            backgroundColor: '00000000',
        },
        transitionSpec: {
            // Sets speed for transition (lower -> faster)
            duration: 500,
            useNativeDriver: true,
        },
        screenInterpolator: sceneProps => {
            // Parses scene props
            const { position, layout, scene, index, scenes } = sceneProps

            // Grabs height and width of screen
            const toIndex = index
            const thisSceneIndex = scene.index
            const height = layout.initHeight
            const width = layout.initWidth

            // Grab index of last screen
            const lastSceneIndex = scenes[scenes.length - 1].index

            // Calculates change in indices
            const deltaScene = (lastSceneIndex - toIndex == 0) ? 1 : (lastSceneIndex - toIndex);

            let translateX = position.interpolate({
                inputRange: [thisSceneIndex - 1, thisSceneIndex],
                // Adjusts how the output get scaled
                outputRange: [width / deltaScene, 0],
            });

            const translateY = position.interpolate({
                // Not used, but in the link they use this for vertical transitions
                // If you're interested in that this would do it
                inputRange: [0, thisSceneIndex],
                outputRange: [height, 0]
            });

            // MAGIC HAPPENS HERE:
            // Test whether we're skipping back more than one screen
            // and slide from bottom if true
            if (lastSceneIndex - toIndex > 1) {
                // If you want the screen to which you are transitioning to not move
                // have return; in this if block (see link). If you want behaviour as 
                // shown in the GIF then leave this
                if (scene.index === toIndex) {
                    return { transform: [{ translateX }] }
                }
                // BIG MAGIC HERE
                // Hide all screens in between
                if (scene.index !== lastSceneIndex) return { opacity: 0 }

            }
            return { transform: [{ translateX }] }
        },
    }),
}
);
<Provider store={store}>
  <ImageBackground source={require('./assets/background.png')} style={styles.backgroundImage} resizeMode='cover'>
    <AppNavigator />
  </ImageBackground>
</Provider>
...
const styles = StyleSheet.create({
  backgroundImage: {
    flex: 1,
  }
});
import { createStackNavigator, CardStyleInterpolators } from 'react-navigation-stack';
import { Easing } from 'react-native';

const Navigator = createStackNavigator({
  // ...
}, {
  defaultNavigationOptions: ({ navigation }) => {
    const animation = navigation.getParam('_animation');
    return {
      // ...
      cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
      ...(animation === 'back' && {
        gestureDirection: 'horizontal-inverted',
      }),
      ...(animation === 'skip' && {
        transitionSpec: {
          open: { animation: 'timing', config: { duration: 0, easing: Easing.step1 }, },
          close: { animation: 'timing', config: { duration: 0, easing: Easing.step0 }, },
        },
      }),
    };
  },
});

// replace to a route not in the stack normally creates a forward animation, but
// we want a backwards animation
this.props.navigation.dispatch(
  StackActions.replace({ routeName: 'Login', params: { _animation: 'back' } })
);