Is it possible to keep a ScrollView scrolled to the bottom?

React Native

React Native Problem Overview


For a chat-like app, I want to keep a ScrollView component scrolled to the bottom, because newest messages appear under the older ones. Can we adjust the scroll position of a ScrollView?

React Native Solutions


Solution 1 - React Native

For React Native 0.41 and later, you can do this with the built-in scrollToEnd method:

<ScrollView
    ref={ref => {this.scrollView = ref}}
    onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>

Solution 2 - React Native

For anyone writing function component that can use hook,

import React, { useRef } from 'react';
import { ScrollView } from 'react-native';

const ScreenComponent = (props) => {
  const scrollViewRef = useRef();
  return (
    <ScrollView
      ref={scrollViewRef}
      onContentSizeChange={() => scrollViewRef.current.scrollToEnd({ animated: true })}
    />
  );
};

Solution 3 - React Native

Use onContentSizeChange to keep track of the bottom Y of the scroll view (height)

https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange

var _scrollToBottomY

<ScrollView
    onContentSizeChange={(contentWidth, contentHeight)=>{
    _scrollToBottomY = contentHeight;
    }}>
</ScrollView>

then use the ref name of the scroll view like

this.refs.scrollView.scrollTo(_scrollToBottomY);

Solution 4 - React Native

Here is the simplest solution I could muster:

 <ListView
ref={ref => (this.listView = ref)}
onLayout={event => {
    this.listViewHeight = event.nativeEvent.layout.height;
}}
onContentSizeChange={() => {
    this.listView.scrollTo({
        y: this.listView.getMetrics().contentLength - this.listViewHeight
    });
}}
/>;

Solution 5 - React Native

In case anyone in 2020 or later is wondering how to achieve this with functional components. This is how I did:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>

Solution 6 - React Native

You can invert the scroll/list view using the react-native-invertible-scroll-view module, then simply call ref.scrollTo(0) to scroll to bottom.

Install the module:

npm install --save react-native-invertible-scroll-view

Then import the component:

import InvertibleScrollView from 'react-native-invertible-scroll-view';

Then use the following JSX instead of a ScrollView:

<InvertibleScrollView inverted
    ref={ref => { this.scrollView = ref; }}
    onContentSizeChange={() => {
        this.scrollView.scrollTo({y: 0, animated: true});
    }}
>
    { /* content */ }
</InvertibleScrollView>

This works because react-native-invertible-scroll-view flips the entire view's content. Note that the view's children will also render in the opposite order to a normal view - the first child will appear at the bottom.

Solution 7 - React Native

try this solution

xcode 10.0

RN: 56.0.0

<ScrollView ref="scrollView"
             onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width

Solution 8 - React Native

Actually @Aniruddha answer doesn't worked for me because I'm using "react-native": "0.59.8" and this.scrollView.root.scrollToEnd also is undefined

but I figured it out and this works this.scrollView.scrollResponderScrollToEnd({animated: true});

If you are using 0.59.8 this will work OR if you are using later version and this works for you. please add versions in this answer so others wont get trouble.

Full Code here

<ScrollView
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{        
        this.scrollView.scrollResponderScrollToEnd({animated: true});
    }}>
</ScrollView>

Solution 9 - React Native

This method is a little bit hacky but I couldn't find a better way

  1. First add a ref to your ScrollView.
  2. Second add a dummy View before closing your ScrollView tag
  3. Get the y position of that dummy View
  4. Whenever you want to scroll to bottom scroll to the position of the dummy View

var footerY; //Y position of the dummy view
render() {    
    return (
      <View>
          <ScrollView 
          ref='_scrollView'>
            // This is where all the things that you want to display in the scroll view goes
            
            // Below is the dummy View
            <View onLayout={(e)=> {
              footerY = e.nativeEvent.layout.y;
              }}/>
          </ScrollView>
              
          //Below is the button to scroll to the bottom    
          <TouchableHighlight
            onPress={() => { this.refs._scrollView.scrollTo(footerY); }}>
            <Text>Scroll to Bottom</Text>
          </TouchableHighlight>
        
      </View>
    );
  }

Solution 10 - React Native

This answers your question: https://stackoverflow.com/a/39563100/1917250

You need to keep constantly scrolling to the bottom of the page by calculating the height of the content minus the height of its scrollView.

Solution 11 - React Native

I guess it is too late to answer but I got one hack! If you use FlatList you can enable inverted property which falls back to setting transform scale to -1 (which is acceptable for other list components like ScrollView ...) . When you render your FlatList with data it always will be on the bottom!

Solution 12 - React Native

If you use TypeScript You need to do this

interface Props extends TextInputProps { 
     scrollRef?: any;
}

export class Input extends React.Component<Props, any> {
     scrollRef;
constructor(props) {
    this.scrollRef = React.createRef();
}
<ScrollView
    ref={ref => (this.scrollRef = ref)}
    onContentSizeChange={() => {
    this.scrollRef.scrollToEnd();
    }}
>
</ScrollView>

Solution 13 - React Native

I fought with this for a while and finally came up with something that worked really well and smooth for me. Like many, I tried .scrollToEnd to no avail. The solution that worked for me was a combination of onContentSizeChange, onLayout props and a little bit more thinking visually about "what scrolling to the bottom" really meant. The last part seems trivial to me now, but it took me forever to figure out.

Given that the ScrollView has a fixed height, when the content height goes over the container's height, I calculated the offset by subtracting the prevHeight (fixed height of the ScrollView) for the currHeight (the content height). If you can visually imagine it, scrolling to that difference in y-axis, slides the content height over its container by that offset. I incremented my offset and made my now current content height my previous height and kept calculating a new offset.

Here is the code. Hope it helps someone. class ChatRoomCorrespondence extends PureComponent { currHeight = 0; prevHeight = 0; scrollHeight = 0;

  scrollToBottom = () => {
    this.refs.scrollView.getScrollResponder().scrollResponderScrollTo({
      x: 0,
      y: this.scrollHeight,
      animated: true
    });
  };

  render() {
    return (
      <ScrollView
        style={Styles.container}
        ref="scrollView"
        onContentSizeChange={(w, h) => {
          this.currHeight = h;

          if (
            this.prevHeight > 0 &&
            this.currHeight - this.scrollHeight > this.prevHeight
          ) {
            this.scrollHeight += this.currHeight - this.prevHeight;
            console.log("--------------------------------------------");
            console.log("Curr: ", this.currHeight);
            console.log("Prev: ", this.prevHeight);
            console.log("Scroll: ", this.scrollHeight);
            this.prevHeight = this.currHeight;
            console.log("PREV: ", this.prevHeight);
            console.log("--------------------------------------------");

            this.scrollToBottom();
          }
        }}
        onLayout={ev => {
          // Fires once
          const fixedContentHeight = ev.nativeEvent.layout.height;
          this.prevHeight = fixedContentHeight;
        }}
      >
        <FlatList
          data={this.props.messages}
          renderItem={({ item }) => (
            <ChatMessage
              text={item.text}
              sender={item.sender}
              time={item.time}
              username={this.props.username}
            />
          )}
          keyExtractor={(item, index) => index.toString()}
        />
      </ScrollView>
    );
  }
}

Solution 14 - React Native

Try setting the contentOffset property of the scroll view to the current height of the content.

To accomplish what you need you could do this as part of the onScroll event. However this may make for a bad user experience so it may prove more user-friendly to only do this when a new message is appended.

Solution 15 - React Native

I had a similar problem, but after reading this page (which give me a headache!) I find this very nice npm package which just invert the ListView and make everything easy for a chat application!!

Solution 16 - React Native

A bit late... but look at this question. https://stackoverflow.com/questions/31883211/scroll-to-top-of-scrollview/3

ScrollView has a "scrollTo" method.

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
QuestionStirmanView Question on Stackoverflow
Solution 1 - React NativeAniruddha ShevleView Answer on Stackoverflow
Solution 2 - React NativecltsangView Answer on Stackoverflow
Solution 3 - React NativedrikodaView Answer on Stackoverflow
Solution 4 - React NativesenornestorView Answer on Stackoverflow
Solution 5 - React NativeMarlon EnglemamView Answer on Stackoverflow
Solution 6 - React NativeirfaanView Answer on Stackoverflow
Solution 7 - React NativeVishal VaghasiyaView Answer on Stackoverflow
Solution 8 - React NativeRajnishCoderView Answer on Stackoverflow
Solution 9 - React NativeSritamView Answer on Stackoverflow
Solution 10 - React NativePaul RadaView Answer on Stackoverflow
Solution 11 - React NativeOriHeroView Answer on Stackoverflow
Solution 12 - React NativeForhadView Answer on Stackoverflow
Solution 13 - React NativeNelly SuguView Answer on Stackoverflow
Solution 14 - React NativeJackView Answer on Stackoverflow
Solution 15 - React NativeMehdi SabouriView Answer on Stackoverflow
Solution 16 - React NativeGeorge BView Answer on Stackoverflow