Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll to bottom of ScrollView in React Native

Tags:

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?

like image 723
coldbuffet Avatar asked Oct 10 '15 02:10

coldbuffet


People also ask

How do I scrollTo the top in React Native?

To scroll to top of the ScrollView with React Native, we assign a ref to the ScrollView and call scrollTo on the ref's value. to create a ref with useRef and set that as the value of the ref prop of the ScrollView . Then we add a Button that calls ref. current.

How do you scrollTo particular view in React Native?

The ScrollView does not provide a method to scroll to a specific list item - but it does provide the methods scrollTo({x, y, animated}) . If your list items are of equal height, you can use them to implement scrolling to a specific item by calling scrollTo({y:itemIndex * ROW_HEIGHT}) .

How do I get ScrollView height in React Native?

Get the height of the contents within the ScrollView ("contentHeight") Use the ScrollView's "onScroll" event to get the scroll offset. Use it to update the scrollOffset animation. Create a ScrollBar component based on the scrollOffset animation value, containerHeight, and contentHeight.


5 Answers

<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})
    }}>
like image 92
Uday Rathod Avatar answered Oct 06 '22 20:10

Uday Rathod


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));
like image 34
KChen Avatar answered Oct 06 '22 20:10

KChen


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.

like image 26
valerybodak Avatar answered Oct 06 '22 19:10

valerybodak


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.

like image 24
sean2078 Avatar answered Oct 06 '22 18:10

sean2078


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.

like image 44
nicholas Avatar answered Oct 06 '22 19:10

nicholas