3

How to know what direction is the user scrolling the ScrollView. I want to show an action button based on the direction. I'm trying to find the direction with the following code:

import React, {Component} from 'react'

import { StyleSheet, Alert, ScrollView, View, Text } from 'react-native' 

class ScrollDirection extends Component {
  constructor(props){
    super(props);
    this.state = {
      offset: 0
    }
  }

  onScroll(event){
    var currentOffset = event.nativeEvent.contentOffset.y;
    var direction = currentOffset > this.offset ? 'down' : 'up';
    this.state.offset = currentOffset;
    Alert.alert(direction);
  }


  render() {
    return (
      <View style={styles.container}>        
        <ScrollView onScroll={this.onScroll}>
          <View style={styles.scroller}>
           <Text style={{fontSize:20,}}>ScrollDirection</Text>
          </View> 
        </ScrollView>
      </View>
    )
  }

}

var styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 50,
  },
  scroller: {
    height: 5000,
  },
});

export default ScrollDirection;

So on Scroll Up I want to alert Up and on Scroll Down alert Down. But I'm getting the following error:

enter image description here

What am I doing wrong? Or is there any better way to do it?

Many thanks!

Update 1:

Changed the state.offset to object, binded onScroll and changed the onScroll function to setState:

constructor(props){
  super(props);
  this.state = {
    offset: {}
  }
  this.onScroll = this.onScroll.bind(this)
}

onScroll(event){
  var currentOffset = event.nativeEvent.contentOffset.y;
  var direction = currentOffset > this.state.offset ? 'down' : 'up';
  this.setState({
        offset : currentOffset.y
      }),
  Alert.alert(direction);
}

But no matter which direction I scroll, I'm getting the Alert as up. What am I missing?

Somename
  • 3,376
  • 16
  • 42
  • 84
  • 1
    Also currentOffset is an object, your state "offset is a number." – ShaneG Dec 01 '17 at 12:21
  • Are you binding the method? `this.onScroll = this.onScroll.bind(this)` in constructor. – G0dsquad Dec 01 '17 at 12:26
  • Thanks .. I updated the question **Update 1** . Atleast no errors with your solutions. The only problem now is that no matter what direction I scroll, I'm getting the alert as `up`. What am i missing ? Many thanks – Somename Dec 01 '17 at 12:33
  • 2
    `this.offset` should be `this.state.offset` as it's what you are tracking each time. – G0dsquad Dec 01 '17 at 12:40
  • Also make sure this.state.offset returns a value – ShaneG Dec 01 '17 at 12:42
  • Updated `var direction = currentOffset > this.state.offset ? 'down' : 'up';` but it still shows only `up` in the alert, no matter what direction I'm scrolling. – Somename Dec 01 '17 at 12:46
  • 1
    Try `console.warn` for the two values you are checking. One might be null which should make it easier to figure out what's wrong. Edit - looks like the below is the answer. You are setting the state variable to essentially `y.y` which will always be null. – G0dsquad Dec 01 '17 at 12:50
  • 2
    I made a mistake there in my solution currentOffset.y should just be currentOffset. Did see it was a variable – ShaneG Dec 01 '17 at 12:51
  • That fixed it! Thanks @G0dsquad an ShaneG – Somename Dec 01 '17 at 12:58
  • @G0dsquad can you please explain on why binding the function here was necessary? – Shubham Bisht Apr 10 '19 at 08:18

2 Answers2

8
constructor(props){
 super(props);
 this.state = {
  offset: 0
 }
}

onScroll(event){
  var currentOffset = event.nativeEvent.contentOffset.y;
  var direction = currentOffset > this.offset ? 'down' : 'up';
  this.state.offset = currentOffset;
  Alert.alert(direction);
}

This should be:

constructor(props){
  super(props);
  this.state = {
   offset: {}
  }
}

onScroll(event){
  var currentOffset = event.nativeEvent.contentOffset.y;
  var direction = currentOffset > this.state.offset ? 'down' : 'up';
  this.setState({
    offset : currentOffset
  }),
 Alert.alert(direction);

}

currentOffset is an object. Answer edited as per request :)

ShaneG
  • 1,498
  • 7
  • 16
  • 2
    This answer should now be edited to be correct as per comments and also add `this.offset` comparison fix :) – G0dsquad Dec 01 '17 at 12:59
6

Ok i found a new way that doesn't uses onscroll property (and it's not called that much). However, be aware that this should not be used to animate a view with the scrollview/flatlist since it only detects when the user stops scrolling , and it may have it's failures ...

Just paste this in your flatlist/scrollview

<Flatlist
...
onScrollBeginDrag={(event)=>{this.init=event.nativeEvent.contentOffset.y}}}
onScrollEndDrag={(event)=>{this.init<event.nativeEvent.contentOffset.y?alert('up'):alert('down')}}
.../>

Useful if you only need to animate something after the user stops scrolling, in my case, a search bar, since i don't want it to animate while the user scrolls down because it will take some valuable space

RegularGuy
  • 3,516
  • 1
  • 12
  • 29