美文网首页react-native开发React Native开发经验集React Native开发
react-navigation转场动画效果(跨页跳转和跨页回跳

react-navigation转场动画效果(跨页跳转和跨页回跳

作者: cp__kong | 来源:发表于2018-07-05 11:41 被阅读259次

    在react-native开发过程中,往往会遇到产品的各种关于转场动画的需求,比如登录页需要从地步modal上来,又或者有这种需求,push的页面是A->B->C->D,然后他要求pop回去的路线是
    D->B->A,这就是跨页回跳,或者还有这种需求,push的页面是A->B->D,然后pop的路线是
    D->C->B->A,C页面在push过程中并不存在。

    1.modal效果

    react-navigation的StackNavigator下的属性mode 可以设置转场效果,但是这边一设置,就是这个导航下所有页面的效果都是这个,也就是要么全是push,要么全是modal,这确实比较坑,不知道最新版的有没有其他解决方案。

    最终我找到了transitionConfig这个属性,这个属性可以自定义转场动画,我在navigate方法中传递一个参数为isModal的参数,默认为false,当需要modal的时候

    this.props.navigation.navigate('XXX',{isModal:true})
    

    然后在router那设置transitionConfig

    const TransitionConfiguration = () => (
    
      {
    
        containerStyle:{},
        screenInterpolator: (sceneProps) => {
          global.sceneProps = sceneProps
          const { scene } = sceneProps;
          const { route } = scene;
          const params = route.params || {};
          const isModal = params.isModal;
          if (isModal){
            //当为`true`时,采用`modal`效果
            return CardStackStyleInterpolator.forVertical(sceneProps);
          }else {
            return CardStackStyleInterpolator.forHorizontal(sceneProps);
          }
        },
    

    2.跨页回跳

    push:A->B->C->D pop:D->B->A

    起初我们找到了goback()方法可以传key,所以采用了在需要回跳的页面设置key,然后在之后的页面回跳回来直接使用goback(key),这样就能回到设置key的页面。

    上面是一种思路,这是由上一个的页面控制下一个页面是否需要保持key,是否需要之后的页面直接回跳到这里,前两天又看了遍react-navigation的api,

     pop: (n, params) =>
        navigation.dispatch(
          NavigationActions.pop({ n, immediate: params && params.immediate })
        ),
    

    发现这个api可以传n,经过尝试是可以直接传n,控制回跳页面数量,当传超过栈的数量时,直接回道栈底。但是这是由后级页面决定回跳几个页面的,逻辑判断要写在触发回跳的页面。

    3.跨页跳转

    push:A->B->D pop:D->C->B->A

    解决方案
    我仔细看了react-navigation的底层文件,发现了他transitionConfig属性可以配置转场动画,CardStackStyleInterpolator对象下默认有5种动画

    export default {
      forHorizontal, //水平,正常push,从右往左
      forVertical,   //modal模式,从下到上
      forFadeFromBottomAndroid,  //安卓的效果
      forFade,  //fade模式
      canUseNativeDriver, //闪一下
    };
    
    

    然后我加了一种模式forHorizontalBack,效果类似back返回,实际上是push,新增了一个方法

    function  forHorizontalBack(props) {
      
      const { layout, position, scene } = props;
      
      if (!layout.isMeasured) {
        return forInitial(props);
      }
      const interpolate = getSceneIndicesForInterpolationInputRange(props);
    
    
    
      if (!interpolate) return { opacity: 0 };
    
      const { first, last } = interpolate;
      const index = scene.index;
      const opacity = position.interpolate({
        inputRange: [first, first + 0.01, index, last - 0.01, last],
        outputRange: [0, 1, 1, 0.85, 0],
      });
    
      const width = layout.initWidth;
      const { scenes } = props;
      const lastSceneIndexInScenes = scenes.length - 1;
      const isBack = !scenes[lastSceneIndexInScenes].isActive;
    
      var translateX
    
      if (isBack){
      //改了动画后造成back的时候pop动画变成了push效果,所以在这边判断,系数用之前的,效果为pop效果
       translateX = position.interpolate({
          inputRange: [first, index, last],
          outputRange: I18nManager.isRTL
            ? [-width, 0, width * 0.3]
            : [width, 0, width * -0.3],
        });
    
      }else {
    
        translateX = position.interpolate({
          inputRange: [first, index, last],
          outputRange: I18nManager.isRTL
            ? [-width, 0, width * 0.3]
            : [width * -0.7, 0, width],//修改了这个系数,效果是本来push从右往左变成从左往右
        });
      }
    
    
      const translateY = 0;
    
      return {
        opacity,
        transform: [{ translateX }, { translateY }],
      };
    
    }
    

    然后在router那设置transitionConfig

    const TransitionConfiguration = () => (
    
      {
    
        containerStyle:{},
        screenInterpolator: (sceneProps) => {
          global.sceneProps = sceneProps
          const { scene } = sceneProps;
          const { route } = scene;
          const params = route.params || {};
          const isModal = params.isModal;
    
          const isSpan = params.span;
          if(isSpan){
    
            return CardStackStyleInterpolator.forHorizontalBack(sceneProps);
          }
    
          if (isModal){
    
            return CardStackStyleInterpolator.forVertical(sceneProps);
          }else {
    
            return CardStackStyleInterpolator.forHorizontal(sceneProps);
          }
    
    
        },
    
    
      })
    

    因为本人原来是做iOS的,项目需要才开始摸索react-native,开发时间也不长,上面的总结如有不正确或者更好的方案,希望大神们多多指教。

    相关文章

      网友评论

      • 9e28948dcdf3:有新方法可以用,支持两种动画,可以看新版本2的最新版
        JaromeHuang:支持两种动画,新的方法是啥, CardStackStyleInterpolator官方确实不可用了删除了
        官网只看到这句话:https://reactnavigation.org/docs/zh-Hans/modal.html ,在最下面的摘要
        更改 stack navigator 上的转换类型,可以使用mode配置项。 当设置为modal时,所有页面加载方式为从下到上滑入,而不是从右到左。 这适用于整个 stack navigator,因此要在其他页面上使用从右到左的转换,我们将使用默认配置添加另一个导航堆栈。

        不知道啥意思
        李剑飞的简书:有新的解决方案吗,统一iOS和android的转场动画,基于 CardStackStyleInterpolator 的已经没办法使用了,官方删除了 CardStackStyleInterpolator ,说这个太消耗内存。。。。
        cp__kong:那跨页回跳这种有没有新的解决方案,modal这种动画的话,其实还好,旧版本也是提供了入口自定义动画的,不需要改第三方文件

      本文标题:react-navigation转场动画效果(跨页跳转和跨页回跳

      本文链接:https://www.haomeiwen.com/subject/yfguuftx.html