React Navigation:将单独的过渡应用于场景

React Navigation: Applying separate transitions to scenes

我想为我的 React Native (iOS) 应用在 React Navigation 中的 StackNavigator 中的场景应用不同的过渡效果。

export const AppNavigator = StackNavigator({
  Home: { screen: Home },
  NewChild: { screen: NewChild },
  Journal: { screen: Journal }
});

我可能希望 NewChild 从下往上加载,就像模式一样。或者我可能希望它从右向左滑入。如果可以定制就太好了。从文档来看,您似乎只能将整个 StackNavigation 设置为 card 或 modal。

正如您已经在文档中看到的那样,现在不可能。您可以跟踪 this issue and this issue requesting this feature. It's on the roadmap for v2,但由于 v1 尚未发布,您最好的选择可能是:

  1. 实施您自己的 transitionConfig 以某种方式处理每个屏幕。我不确定这是否可行。
  2. 使用 main issue 中的想法派生一个工具。或者简单地让你的 fork 特定于你的代码并维护它直到问题得到解决。

感谢线程中的每个人,它对我有用。

我有很多场景只由一个 StackNavigator 管理,我想为其中一些制作不同的动画。

首先,我在我的路由器中设置了一个常量,其中包括每个场景我想显示水平过渡:

const horizontalTransitionScenes = [
  AddContact,
];

之后,我使用 StackNavigator 设计了我的应用程序路由器:

const App = StackNavigator({
  AddContact: {
    screen: AddContact,
  },
  EditContact: {
    screen: EditContact,
  },
});

我使用 CardStackStyleInterpolator 来修改场景之间的转换。我可以这样导入:import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';

我们现在可以将 transitionConfig 参数添加到我们的 StackNavigator 以根据我们的场景显示不同的动画:

 const App = StackNavigator(
{
    AddContact: {
        screen: AddContact
    },
    EditContact: {
        screen: EditContact
    }
},
{
    transitionConfig: (currentState: any) => {
        if (
            currentState.scenes[
                currentState.scenes.length - 1
            ].route.routeName.includes(horizontalTransitionScenes)
        ) {
            return {
                screenInterpolator: CardStackStyleInterpolator.forHorizontal
            };
        }
        return {
            screenInterpolator: CardStackStyleInterpolator.forVertical
        };
    }
}
);

通过 StackNavigator 实现,您将能够为您想要的场景显示不同类型的动画。

祝你有美好的一天

我可以通过一些条件逻辑来完成这个,我们在 react-navigation 3.3.2.

您必须从 react-native 导入 EasingAnimated 然后您可以按名称或索引(下面是按名称)有条件地渲染特定屏幕的转换.

通过在导航器 外部 声明配置,并使用 {} 切换 transitionSpec 它只会在该特定屏幕上触发 - 与screenInterpolator 的条件。

Screen1Screen2 有动画,但 none 的其他屏幕有那个动画。

const screen2Config = {
  duration: 300,
  easing: Easing.out(Easing.poly(4)),
  timing: Animated.timing,
};

export const ScreenStack = createStackNavigator({
  Screen1: {
    screen: Screen1,
    navigationOptions: ({ navigation }) => ({
      headerTitle: 'Screen1',
      headerTitleAllowFontScaling: false,
    }),
  },
  Screen2: {
    screen: Screen2,
    navigationOptions: ({ navigation }) => ({
      headerTitle: 'Screen2',
      headerTitleAllowFontScaling: false,
      tabBarVisible: false,
    }),
  },
  Screen3: {
    screen: Screen3,
    navigationOptions: ({ navigation }) => ({
      headerTitle: 'Screen3',
      headerTitleAllowFontScaling: false,
    }),
  },
  Screen4: {
    screen: Screen4,
    navigationOptions: ({ navigation }) => ({
      headerTitle: 'Screen4',
      headerTitleAllowFontScaling: false,
    }),
  },
}, {
  headerMode: 'float',
  mode: 'modal',
  transitionConfig: sceneProps => ({
    transitionSpec: sceneProps.scene.route.routeName === 'Screen2' ? screen2Config : {},
    screenInterpolator: (sceneProps) => {
      if (sceneProps.scene.route.routeName === 'Screen2') {
        const { layout, position, scene } = sceneProps;
        const { index } = scene;

        const width = layout.initWidth;
        const translateX = position.interpolate({
          inputRange: [index - 1, index, index + 1],
          outputRange: [width, 0, 0],
        });

        const opacity = position.interpolate({
          inputRange: [index - 1, index - 0.99, index],
          outputRange: [0, 1, 1],
        });

        return { opacity, transform: [{ translateX }] };
      }
    },
  }),
});