Detect ScrollView has reached the end

React NativeReact Native-Scrollview

React Native Problem Overview


I have a Text with long text inside a ScrollView and I want to detect when the user has scrolled to the end of the text so I can enable a button.

I've been debugging the event object from the onScroll event but there doesn't seem any value I can use.

React Native Solutions


Solution 1 - React Native

I did it like this:

import React from 'react';
import {ScrollView, Text} from 'react-native';
    
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
  const paddingToBottom = 20;
  return layoutMeasurement.height + contentOffset.y >=
    contentSize.height - paddingToBottom;
};
    
const MyCoolScrollViewComponent = ({enableSomeButton}) => (
  <ScrollView
    onScroll={({nativeEvent}) => {
      if (isCloseToBottom(nativeEvent)) {
        enableSomeButton();
      }
    }}
    scrollEventThrottle={400}
  >
    <Text>Here is very long lorem ipsum or something...</Text>
  </ScrollView>
);
    
export default MyCoolScrollViewComponent;

I wanted to add paddingToBottom because usually it is not needed that ScrollView is scrolled to the bottom till last pixel. But if you want that set paddingToBottom to zero.

Solution 2 - React Native

As people helped here I will add the simple code they write to make reached to top and reached to bottom event and I did a little illustration to make things simpler

Layout and vars values

<ScrollView
onScroll={({nativeEvent})=>{
if(isCloseToTop(nativeEvent)){
    //do something
}
if(isCloseToBottom(nativeEvent)){
   //do something
}
}}
>
...contents
</ScrollView>



isCloseToBottom({layoutMeasurement, contentOffset, contentSize}){
   return layoutMeasurement.height + contentOffset.y >= contentSize.height - 20;
}



ifCloseToTop({layoutMeasurement, contentOffset, contentSize}){
   return contentOffset.y == 0;
}

Solution 3 - React Native

<... onScroll={(e) => {
        let paddingToBottom = 10;
        paddingToBottom += e.nativeEvent.layoutMeasurement.height;
        if(e.nativeEvent.contentOffset.y >= e.nativeEvent.contentSize.height - paddingToBottom) {
          // make something...
        }
      }}>...

like this react-native 0.44

Solution 4 - React Native

For Horizontal ScrollView (e.g. Carousels) replace isCloseToBottom function with isCloseToRight

isCloseToRight = ({ layoutMeasurement, contentOffset, contentSize }) => {
    const paddingToRight = 20;
    return layoutMeasurement.width + contentOffset.x >= contentSize.width - paddingToRight;
};

Solution 5 - React Native

@Henrik R's right. But you should use Math.ceil() too.

function handleInfinityScroll(event) {
        let mHeight = event.nativeEvent.layoutMeasurement.height;
        let cSize = event.nativeEvent.contentSize.height;
        let Y = event.nativeEvent.contentOffset.y;
    
        if(Math.ceil(mHeight + Y) >= cSize) return true;
        return false;
}

enter image description here

Solution 6 - React Native

Another solution could be to use a ListView with a single row (your text) which has onEndReached method. See the documentation here

Solution 7 - React Native

As an addition to the answer of Henrik R:

If you need to know wether the user has reached the end of the content at mount time (if the content may or may not be too long, depending on device size) - here is my solution:

<ScrollView 
        onLayout={this.onLayoutScrollView}
        onScroll={this.onScroll}>
    <View onLayout={this.onLayoutScrollContent}>
        {/*...*/}
    </View>
</ScrollView>

in combination with

onLayout(wrapper, { nativeEvent }) {
    if (wrapper) {
        this.setState({
            wrapperHeight: nativeEvent.layout.height,
        });
    } else {
        this.setState({
            contentHeight: nativeEvent.layout.height,
            isCloseToBottom:
              this.state.wrapperHeight - nativeEvent.layout.height >= 0,
        });
    }
}

Solution 8 - React Native

const isCloseToBottom = async ({ layoutMeasurement, contentOffset, contentSize }) => {
const paddingToBottom = 120
return layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom}


 <ScrollView
    onMomentumScrollEnd={({ nativeEvent }) => {
      if (isCloseToBottom(nativeEvent)) {
        loadMoreData()
      }
    }}
    scrollEventThrottle={1}
  >

Above answer is correct but to callback on reaching the end in scrollView use onMomentumScrollEnd not onScroll

Solution 9 - React Native

I use ScrollView and this worked for me

Here is my solution:

I passed onMomentumScrollEnd prop to scrollView and on the basis event.nativeEvent I achieved onEndReached functionality in ScrollView

 onMomentumScrollEnd={(event) => { 
          if (isCloseToBottom(event.nativeEvent)) {
            LoadMoreRandomData()
          }
         }
       }}

  const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
  contentSize.height - paddingToBottom;

};

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEldelshellView Question on Stackoverflow
Solution 1 - React NativeHenrik RView Answer on Stackoverflow
Solution 2 - React NativeMhd Louay Al-oshView Answer on Stackoverflow
Solution 3 - React NativebluevariantView Answer on Stackoverflow
Solution 4 - React Nativedeadcoder0904View Answer on Stackoverflow
Solution 5 - React NativeFuad CavadovView Answer on Stackoverflow
Solution 6 - React NativeDavidView Answer on Stackoverflow
Solution 7 - React NativeMalte PetersView Answer on Stackoverflow
Solution 8 - React NativeMohammad ZeeshanView Answer on Stackoverflow
Solution 9 - React NativeAwais IbrarView Answer on Stackoverflow