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?
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.
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}) .
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.
<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})
}}>
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));
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With