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
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 (
{
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;
}}
>
(
)}
keyExtractor={(item, index) => index.toString()}
/>
);
}
}