ericvicenti / navigation-rfc

Better Navigation in React Native
440 stars 44 forks source link

Data structure for navigation states transition #7

Open hedgerwang opened 8 years ago

hedgerwang commented 8 years ago

Hi

I'd like to talk about state transition.

In most cases, views are not rendering against the navigation state. Instead, it's rendered with the states transition.

Let's assume that the navigation state is just a simple list of routes

for example,

[A, B, C]

and say that we want to replace route C with route D, so that the navigation state shall look like this

[A, B, D]

the question is, when the navigation transition is presented with animation, we'd have to provide both the old state, the new state, and also the progress value that indicates the progressiveness of the transition between the two state.

do you have anything in mind to solve this kind of problem?

Thanks.

ericvicenti commented 8 years ago

I'm assuming this issue is specific to NavigationAnimatedStackView, so I'll explain how it should work, and we can discuss any issues that might arise from my current plan.

Right now the NavigationAnimatedStackView asks the developer to define renderScene, which will get re-called whenever the scene record changes. A scene record is defined by the route, index, the shared dynamic progress value, and isStale when the scene is animating away. So whenever the route changes, the index gets moved, or the route becomes stale, the NavigationAnimatedStackView should re-call renderScene

To address your concern, a scene view (like NavigationCard) could implement special behavior on componentWill/DidRecieveProps to handle transitions.

This is how I think it should work, but I should warn you: the current implementation might not work exactly this way yet- I think it calls renderScene too often.

Thanks for all your help and feedback @hedgerwang! You paved the way for many of these ideas like the immutable NavigationStack/State and the scene/transition record.

sahrens commented 8 years ago

@hedgerwang: are you thinking about an animated transition (like a cross-fade) from route C to D since the top of the stack is being replaced? @ericvicenti: I'm not sure how that would be solved by your explanation because both stacks and rendered views would need to stay alive until the animation completes....would that be handled in a custom NavigationCard or something?

hedgerwang commented 8 years ago

@sahrens yes.

Below is the pseudo codes to demonstrate how I think the transition of stack should be handled and rendered for the view.

const MyNavigationView = React.createClass({
  getInitialState() {
    var trasition = new NavigationTransition({
      stack: this.props.stack,
      onComplete: this.forceUpdate.bind(this),
    }),
    return {
      transtion,
    },
  }

  componentWillReceiveProps(nextProps) {
    const transtion = this.state.transtion.to(nextProps.stack);
    if (transtion !== this.state.transtion) {
      this.setState({transtion});
    }
  },

  render() {
    return <View>{this.state.transiton.records.map(this._renderScene)}</View>;
  }

  _renderScene(record: NavigationTransitionRecord) {
    return (
      <Animated.View key={record.key} style={record.style}>
        {this.props.renderScene(
          record.route, 
          record.stack, 
          record.index, 
          route.active,
        )}
      </Animated.View>
    );  
  }
});

The transition object NavigationTransition maintains a list of records that can be used to render the stack transition between the stacks which include both the stale and active route.

ericvicenti commented 8 years ago

I'm a bit confused. Is this question about the animation of a route 'replace'? I don't know what that animation would even look like- would it be like animating forward, or back?

This is why I find it easier to just think about position.

hedgerwang commented 8 years ago

The question is about stacks transition. Specifically, a data type that contains the information the the two stacks (before and after) that are transitioning from one to another.

ericvicenti commented 8 years ago

Do we want the complexity of that? I hope to keep things simple so people can quickly write their own navigation views/animations/gestures.

hedgerwang commented 8 years ago

There can be unlimited type of animations, but we should try to provide the standard way to represent the data needed for transition.

For instance, a AnimatedNavigationBar wants to react to the AnimatedPagerView which would have to expose the transition state.

If we do do this, people would build their own APIs that are hard to work across multiple navigation views.

sahrens commented 8 years ago

Would it be possible to provide a simple hook that people could use to do the transition animation (with some jankiness) that by default does nothing, without increasing the complexity of much else? I'm not too worried about making it easy/elegant to do these kinds of transitions, but it should be possible without too much awefulness?

Also, it would be awesome if we could support transitions like this without too much effort:

http://developer.android.com/training/material/animations.html#Transitions

On Fri, Jan 15, 2016 at 10:50 AM, Eric Vicenti notifications@github.com wrote:

Do we want the complexity of that? I hope to keep things simple so people can quickly write their own navigation views/animations/gestures.

— Reply to this email directly or view it on GitHub https://github.com/ericvicenti/navigation-rfc/issues/7#issuecomment-172050077 .

ericvicenti commented 8 years ago

@hedgerwang What APIs will people build that you are worried about? The NavigationBar example you mentioned could receive a navState and a position as props- no transition data structure needed. If people have more advanced or special-purpose needs, I would encourage them to build something more complicated than NavigationAnimatedView.

@sahrens, that material design transition is awesome, I hadn't seen it before! It should be totally supported, but you'd need to write code that does measurement and augments the action as it gets passed up. Then the action has all the data it needs to configure the animation correctly.

To help us discuss the NavigationAnimatedView question, it would be useful to describe a specific use case. I still can't think of a use case that is totally unsupported.

sahrens commented 8 years ago

Actually, I think you could build any "replace" transition as a push and then a remove after the animation (e.g. a cross-fade) completes - any examples where that wouldn't work? e.g.

[A, B] ={push (C) with cross-fade}=> [A,B,C] ={remove B}=> [A,C]

Seems like that could be done fairly easily?

On Fri, Jan 15, 2016 at 11:44 AM, Eric Vicenti notifications@github.com wrote:

@hedgerwang https://github.com/hedgerwang What APIs will people build that you are worried about? The NavigationBar example you mentioned could receive a navState and a position as props- no transition data structure needed. If people have more advanced or special-purpose needs, I would encourage them to build something more complicated than NavigationAnimatedView.

@sahrens https://github.com/sahrens, that material design transition is awesome, I hadn't seen it before! It should be totally supported, but you'd need to write code that does measurement and augments the action as it gets passed up. Then the action has all the data it needs to configure the animation correctly.

To help us discuss the NavigationAnimatedView question, it would be useful to describe a specific use case. I still can't think of a use case that is totally unsupported.

— Reply to this email directly or view it on GitHub https://github.com/ericvicenti/navigation-rfc/issues/7#issuecomment-172064706 .

ericvicenti commented 8 years ago

Yep, but it means you are in an invalid [ABC] navigation state for a period of time. So this is still something worth thinking about.