Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scrollable within PanController #1

Open
morgante opened this issue Aug 8, 2015 · 10 comments
Open

Scrollable within PanController #1

morgante opened this issue Aug 8, 2015 · 10 comments

Comments

@morgante
Copy link

morgante commented Aug 8, 2015

Thanks for making this little module!

I'm trying to implement some functionality but can't seem to get it to work correctly. What I essentially want is a scrollable pane which can be enlarged. When first opened, it would be 50% of the viewport height, but you can drag it upward and it will reach 100% of the viewport height. Once at 100% viewport height (ie. it is the entire viewport), you could scroll the contents. You could downsize it back to being 50% of the viewport by scrolling back to the top and dragging down.

Does that make sense? Is it possible to do this using PanController?

My trouble comes with the interaction between the ScrollView and the PanController—the ScrollView never takes over, so you can't scroll its contents.

@lelandrichardson
Copy link
Owner

Hi @morgante

Thanks for your question... I still haven't really "released" this component yet, so there are still some things that that I have left to implement and might not work correctly...

With that out of the way, let me see if I can understand what you are trying to do...

Using a ScrollView inside the PanController will likely never be possible. The PanController is meant to emulate things like the ScrollView (and additional behavior like you are wanting).

If I understand what you are trying to do, this should be pretty easy. Is there an app that already does this where you are trying to emulate the behavior? If you can post a gif of the UI, I can try and emulate it for you. If not, here is what I would recommend doing:

  1. Use the PanController to emulate the scrollview entirely. This can be done by simple enabling the vertical option and passing in an Animated.Value to the panY.
  2. Create a translateY interpolated value from your panY value like so:
var translateY = this.state.panY.interpolate({
  inputRange: [0, breakpoint, breakpoint+1],
  outputRange: [0,0,1]
})
  1. Apply this value to the translateY of the inner view
  2. Create a height interpolated value from your panY value like so:
var height = this.state.panY.interpolate({
  inputRange: [0, breakpoint, breakpoint+1],
  outputRange: [starting_height, screen_height, screen_height]
})
  1. Apply the height value to the height of the inner view.
  2. You'll probably also have to tweak some things like the height of the container using the measure API. This is one of the things I have left to abstract out into the PanController component, but for now you'll have to do this manually.

Note: my ScrollView implementation would be a good starting point: https://github.com/lelandrichardson/react-native-pan-controller/blob/master/lib/ScrollView.js

@morgante
Copy link
Author

Thanks for the pointers. I think that makes sense, but how do you handle the transition from scrolling within the pane to scrolling the pane down (decreasing its size).

The effect I'm trying to achieve can be seen in the Facebook Paper app. The cards at the bottom of the screen can be dragged left and right, or up, which increases their size until they take over the screen and become scrollable.

@lelandrichardson
Copy link
Owner

@morgante can you record a gif? The transition should be able to be handled through proper use of interpolation

@olivierlesnicki
Copy link

@morgante is it something like this https://github.com/olivierlesnicki/react-native-switcher you're trying to achieve?

I've only just discovered react-native-pan-controller and I'm currently thinking about using it for the example above.

@olivierlesnicki
Copy link

The more I think of it, the less I think it's possible. You'd need a way to compute an Animated value based on the values of the panX and panY (looks like a good example for Animated.Formula)

I'm actually trying to achieve the same thing:

var React = require('react-native');
var PanController = require('react-native-pan-controller').PanController;

var Switcher = React.createClass({

  getDefaultProps() {

    var scroll = new React.Animated.Value(0);
    var zoom = new React.Animated.Value(0);

    return {
      scroll: scroll,
      zoom: zoom,
    };
  },

  getInitialState() {
    return {
      width: 0,
      height: 0,
    };
  },

  layout(e) {
    this.setState({
      width: e.nativeEvent.layout.width,
      height: e.nativeEvent.layout.height,
    });
  },

  render() {

    var children = this.props.children.map ? this.props.children[this.props.children];

    return (
      <React.View
        onLayout={this.layout}
        style={{
          flex: 1,
        }}
      >
        <PanController
          momentumDecayConfig={{
            decceleration: 0.1,
          }}
          horizontal={true}
          vertical={true}
          overshootX='spring'
          overshootY='spring'
          lockDirection={true}
          snapSpacingX={this.state.width}
          snapSpacingY={this.state.height / 6}
          xBounds={[-this.state.width * (this.props.children.length - 1), 0]}
          yBounds={[0, this.state.height / 3]}
          panX={this.props.scroll}
          panY={this.props.zoom}
          style={{
            flex: 1,
          }}
        >
          {children.map((child, i) => {

            var delta = this.props.scroll.interpolate({
              inputRange: [-this.state.width * (i + 1), -this.state.width * i],
              outputRange: [-1, 0],
            });

            var translateX = delta.interpolate({
              inputRange: [-1, 0, 0.5, 1],
              outputRange: [-this.state.width / 8, 0, this.state.width / 4, 2 * this.state.width / 3],
            });

            var translateY = this.props.zoom;

            var scale = delta.interpolate({
              inputRange: [0, 1],
              outputRange: [0.73, 0.75],
            });

            return (
              <React.Animated.View
                key={i}
                style={[{
                  position: 'absolute',
                  top: 0,
                  left: 0,
                  right: 0,
                  bottom: 0,
                  transform: [
                    {translateX},
                    {translateY},
                    {scale},
                  ],
                },]}>
                {child}
              </React.Animated.View>
            );
          })}
        </PanController>
      </React.View>
    );
  }
});

module.exports = Switcher;

I'd like to add the ability to zoom-in (instead of panY) the card and expand them full-width. Once they reach full-width, I want them to scroll without overlapping (like a normal scrollview).

@morgante
Copy link
Author

@olivierlesnicki Yup, that's pretty much the same effect I was trying to go for.

I ended up writing the code myself directly using React Native.

@smontlouis
Copy link

@morgante Can you show me what you did please ? I'm stuck with the same issue.

@lelandrichardson
Copy link
Owner

@morgante @bulby97 @olivierlesnicki I'm going to start working on this project again, so I might be able to help you...

That react-native-switcher is pretty slick. i think this can be accomplished using the PanController.

Within the next week I hope to release some updates to this module which will include Android compatibility, and several working examples. I will also give a go at including a "Switcher" component like the react-native-switcher.

Hopefully with that example you may be able to extrapolate to your own needs?

@olivierlesnicki
Copy link

Good job! Look forward to it @lelandrichardson

@gendronb
Copy link

Nice work @lelandrichardson. Any progress regarding Android support?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants