coldbuffet
coldbuffet

Reputation: 2565

Scroll to bottom of ScrollView in React Native

I would like to find a way to programmatically scroll to the bottom of a scrollView. I am aware of the scrollTo method after looking at the source code for ScrollView, however I cannot seem to find a way to measure the content size of the scrollView.

After looking around, I came across this github issue that mentions to look at how "UIManager.measureX methods are used" to measure content size. However after searching several times through the source code, I cannot quite seem to find where these methods are used.

Would someone be able to point me in the right direction?

Upvotes: 10

Views: 19109

Answers (5)

Uday Rathod
Uday Rathod

Reputation: 19

<ScrollView ref={scrollView => this.scrollView = scrollView}
      onContentSizeChange={( contentWidth, contentHeight ) => {
        this._contentHeight = contentHeight;
        console.log('Height: ' + this._contentHeight);
        this.scrollView.scrollTo({ y: this._contentHeight , animated: true})
    }}>

Upvotes: 1

nicholas
nicholas

Reputation: 14563

There's a better way to do this. In broad strokes:

Use a ListView to render the chat.

<ListView
  ref="list"
  ...

Add a footer to the list with renderFooter that uses onLayout to save its y position. The footer doesn't have to render anything visible, just an empty View. All you're looking for is where the bottom of the list is.

renderFooter={() => {
  return <View onLayout={(e)=> {
    this.footerY = e.nativeEvent.layout.y;
  }}/>
}},

Add an onLayout handler to the ListView itself that saves the lists height.

onLayout={(e)=>{
  this.listHeight = e.nativeEvent.layout.height;
}}

With those two bits of information you can scroll to the bottom of the list with something like:

if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
  var scrollDistance = this.listHeight - this.footerY;
  var scrollResponder = this.refs.list.getScrollResponder();
  scrollResponder.scrollWithoutAnimationTo(-scrollDistance);
}

How often you scroll to the bottom is up to you and depends on the behavior you want.

An example of this in action is GiftedMessenger.

Upvotes: 1

KChen
KChen

Reputation: 1918

It was pretty consealed and I ran into the source code.

You can try like this:

require:

var RCTUIManager = require('NativeModules').UIManager;

render:

<ScrollView ref = {component=>{this._scrollView=component;}}>
</ScrollView>

event:

someEvent: function() {
  RCTUIManager.measure(this._scrollView.getInnerViewNode(), (...data)=>{console.log(data)});
}

From the data, you can get the contentsize of the scrollview whose height is the fourth element of data. Of course you can get the content offset from it. Run into the source code of RCTUIMananger.m for more details.

When you use getInnerViewNode you can get the frame of ScrollView's inner view's frame. If you want to get the ScrollView's frame, you should use React.findNodeHandle(this._scrollView), and ScrollView's frame is not always equals to its inner view's frame.


(updated)

If you want to replace (...data)=>{console.log(data)} with callback, you should use it like this:

RCTUIManager.measure(this._scrollView.getInnerViewNode(), callback.bind(this));

Upvotes: 14

valerybodak
valerybodak

Reputation: 4413

Yo can use scrollToEnd() method of the ScrollView:

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

According to the documentation: If this is a vertical ScrollView scrolls to the bottom. If this is a horizontal ScrollView scrolls to the right.

Upvotes: 3

sean2078
sean2078

Reputation: 5440

While RCTUIManager.measure() does work by extracting the 4th element of the data array via reference, it's much more appropriate ( and easier ) to use the following when working with ScrollViews:

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

onContentSizeChange={( contentWidth, contentHeight ) => {
    this._contentHeight = contentHeight
}}

This event will fire once the inner child components finish laying out and upon change. This works for me and I recommend this supported approach when determining content bounds.

Upvotes: 1

Related Questions