Skip to content

[Navigator] Animated replace #1981

Closed
facebookarchive/react-native-custom-components
#8

Description

@DaleLJefferson

I often find myself wanting to "replace" a route i.e not adding to the history yet have the route change animate.

In iOS I would do something like this.

[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];

Maybe this is related to issue #1953 I think I would prefer an api where we could do

replace(route, animated);
push(route, animated);

Activity

  1. jeanregisser commented on Jul 13, 2015

    @jeanregisser
    Contributor

    Was thinking about the same.
    If we can agree on an API I would gladly submit a PR implementing it.

  2. sahrens commented on Jul 15, 2015

    @sahrens
    Contributor

    What do you think, Eric?

  3. ericvicenti commented on Jul 15, 2015

    @ericvicenti
    Contributor

    I think the API looks reasonable, and we have actually experimented with something similar. We're working on some big changes to Navigator to get the route stack logic out, and to upgrade to the new Animated API. This should be pretty easy to add when we make those changes

  4. grabbou commented on Jul 17, 2015

    @grabbou
    Contributor

    Animated replace would've been awesome! I often find it useful to replace main view controller when using e.g. side menu. Unfortunately, I am quite limited currently, so waiting for the updates in this matter

  5. miracle2k commented on Sep 8, 2015

    @miracle2k

    I'm doing something like this now to skip a payment screen route that I really don't want in the stack:

          var r = navigator.getCurrentRoutes();
          var backCount = 1;
          if (route.props.fromPayment)
            backCount = 2;
          navigator.popToRoute(r[r.length-1-backCount]);  
    

    It works, but I'd really rather not have this screen have the responsibility to know about the previous routes.

  6. grabbou commented on Sep 9, 2015

    @grabbou
    Contributor

    @miracle2k for this specific use case, take a look at our implementation https://github.com/este/native/blob/master/src/app/app.react.js#L105-L108. We are decorating Navigator with few handy methods and passing it down, this particular one works quite well.

  7. ericvicenti commented on Oct 6, 2015

    @ericvicenti
    Contributor

    For now maybe you could do a push and then immediatelyResetRouteStack once the transition completes

  8. chirag04 commented on Oct 6, 2015

    @chirag04
    Contributor

    @ericvicenti cool. so immediatelyResetRouteStack in didfocus should do the trick?

  9. miracle2k commented on Oct 10, 2015

    @miracle2k

    Inspired by the suggestion from @grabbou, I am now using this workaround:

    function betterNavigator(navigator) {
      const navigation = {
        pop: () => {
          debugger;
          const routes = navigator.getCurrentRoutes();
    
          // Find the next route without replace mode
          var target = null;
          for (let i=routes.length-2; i>=0; i--) {
            if (!routes[i].replace) {
              target = routes[i];
              break;
            }
          }
    
          if (target)
            navigator.popToRoute(target);
          else
            navigator.pop();
        },
        popToTop: navigator.popToTop,
        popToRoute: navigator.popToRoute,
        popBack: (index) => {
          const routes = navigator.getCurrentRoutes();
          navigator.popToRoute(routes[routes.length - index - 1]);
        },
        replaceAtIndex: navigator.replaceAtIndex,
        push: navigator.push,
        replace: (target) => {
          debugger;
          const routes = navigator.getCurrentRoutes();
          routes[routes.length-1].replace = true;
          navigator.push(target);
        },
        getCurrentRoutes: navigator.getCurrentRoutes
      };
      return navigation;
    }
    

    Note the overwrites of replace() and pop(). pop will skip all routes that have been replaced.

  10. fender commented on Dec 2, 2015

    @fender

    @miracle2k Although that allows replace to use the animations from push, I don't think it behaves the same. replace() will unmount the current component and then mount the new one immediately.

  11. DickyT commented on Jan 20, 2016

    @DickyT

    @miracle2k @fender I found this problem too, the view i want to replace was a view which using camera, and using this way the camera page cannot be unmounted and it is keep using the camera, which makes my App deny by App Store because of something like "using camera background". I am now using setTimeout to push new view back after poping current view.

    Hope next official release can fix this.

  12. ssh-randy commented on Feb 4, 2016

    @ssh-randy

    I still find this problem as well, when I have sceneconfig set, it does not work for type replace even though it does for pop

  13. aksonov commented on Feb 4, 2016

    @aksonov

    Any ETA on this, @ericvicenti ?

  14. aksonov commented on Feb 4, 2016

    @aksonov

    Looks like following code works well, could it be used as workaround?

    navigator.immediatelyResetRouteStack(navigator.getCurrentRoutes().splice(-1,1));
    navigator.push(ROUTE);
    
  15. 4 remaining items

  16. vaukalak commented on May 27, 2016

    @vaukalak

    For now I use this workaround:
    https://gist.github.com/vaukalak/40ed12eadf0f605a8ffc4584144f2fdd

    then in my code I do:

    if(!this.navigatorUtils) {
        this.navigatorUtils = navigatorUtils(this.refs['navigator']);
    }
    this.navigatorUtils.resetToAnimated(props.screen);
    

    not too elegant, but seems to work :)

  17. zhaotai commented on Jun 3, 2016

    @zhaotai

    I have tried all of these solutions above but all didn't work.
    So I had to check the Navigator source code while coded on my own. Finally after solving some problems such as flashing and animating, not working at all, replacing without animation though I have written the code, I got the solution.

    These are my code below. Most of them are copied from Navigator source code. What I did is just combine them in a right way. Um...of course, they still can be optimized. And they too much hard to understand. Trust me, I won't understand after tonight. But it works. It's enough.
    BTW, my RN is 0.27.

    Navigator.prototype.replaceWithAnimation = function (route) {
      const activeLength = this.state.presentedIndex + 1;
      const activeStack = this.state.routeStack.slice(0, activeLength);
      const activeAnimationConfigStack = this.state.sceneConfigStack.slice(0, activeLength);
      const nextStack = activeStack.concat([route]);
      const destIndex = nextStack.length - 1;
      const nextSceneConfig = this.props.configureScene(route, nextStack);
      const nextAnimationConfigStack = activeAnimationConfigStack.concat([nextSceneConfig]);
    
      const replacedStack = activeStack.slice(0, activeLength - 1).concat([route]);
      this._emitWillFocus(nextStack[destIndex]);
      this.setState({
        routeStack: nextStack,
        sceneConfigStack: nextAnimationConfigStack,
      }, () => {
        this._enableScene(destIndex);
        this._transitionTo(destIndex, nextSceneConfig.defaultTransitionVelocity, null, () => {
          this.immediatelyResetRouteStack(replacedStack);
        });
      });
    };
    

    After defining that in prototype, you can use it anywhere you want.
    Just like
    navigator.replaceWithAnimation(route);

  18. waleedarshad-vf commented on Jun 25, 2016

    @waleedarshad-vf

    Performace is too slow above provide method, can anyone optimized it

  19. zhaotai commented on Jun 28, 2016

    @zhaotai

    @waleedarshad-vf I used it in online production and after compiling them by react native and set to production mode. It's quite fluent. Have you tried the production mode?

  20. waleedarshad-vf commented on Jun 28, 2016

    @waleedarshad-vf

    @zhaotai thanks for you reply. I tried it again last day and it is working now. i don't know what happened that time. it might be due to low memory of the device.

  21. zhaotai commented on Jun 29, 2016

    @zhaotai

    @waleedarshad-vf Yeah, especially you develop in the simulator. The application memory will increase along with your code complication increasing and as a result the navigating and animation which is implemented by js code instead of native module will become slow and unsmooth.

  22. waleedarshad-vf commented on Jul 1, 2016

    @waleedarshad-vf

    @zhaotai one thing to be mention here that it is not as smooth as the push method of Navigator but thanks for Awesome work

  23. waleedarshad-vf commented on Jul 13, 2016

    @waleedarshad-vf

    @zhaotai it needs attention to make it as smooth as push method. the tester here points out this jerk animation issue in a single attempt.

  24. zhaotai commented on Jul 18, 2016

    @zhaotai

    @waleedarshad-vf I will try, thanks for suggestion. Maybe you can improve it, too.

  25. mkonicek commented on Oct 27, 2016

    @mkonicek
    Contributor

    Hi there! This issue is being closed because it has been inactive for a while.

    But don't worry, it will live on with ProductPains! Check out its new home: https://productpains.com/post/react-native/navigator-animated-replace

    ProductPains helps the community prioritize the most important issues thanks to its voting feature.
    It is easy to use - just login with GitHub. GitHub issues have voting too, nevertheless
    Product Pains has been very useful in highlighting the top bugs and feature requests:
    https://productpains.com/product/react-native?tab=top

    Also, if this issue is a bug, please consider sending a pull request with a fix.
    We're a small team and rely on the community for bug fixes of issues that don't affect fb apps.

  26. added a commit that references this issue on Jun 16, 2017
    95de74d
  27. locked as resolved and limited conversation to collaborators on Jul 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions