6

When you use ScrollView or ListView in your ReactNative app and some new data came in, the default behavior of them is to keep the position in the Scroll component. Which means if the new data of height 20 came in when you're at the middle of the ScrollView, on-screen items will slide by 20 and sometimes it will go off the screen.

Is there any way to keep/track the position? for example, if the new data of height 20 came in, the position automatically adjust the position by 20 so that current on screen items keep on the screen. Thanks in advance.

Dave
  • 405
  • 4
  • 17
  • 1
    This might help you http://stackoverflow.com/a/36803008/3790046 – Henrik R Dec 22 '16 at 06:16
  • 1
    @HenrikR Yea thats definitely a alternative way of doing it but it's calling the position change in onContentSizeChange, which means it adjust the position after the content size has already changed and would change the position after that so it's gonna come up against bad UX. – Dave Dec 22 '16 at 21:24

2 Answers2

4

I have a working solution, although it's not very smooth, it does the job:

handleScroll = (event) => {
  this.scroll = event.nativeEvent.contentOffset.y
  if (this.ready && this.scroll < SCROLL_TRIGGER) {
    // load more stuff here
  }
}

handleSize = (width, height) => {
  if (this.scroll) {
    const position = this.scroll + height - this.height
    this.refs.sv.scrollTo({x: 0, y: position, animated: false})
  }
  this.height = height
}

// render:

<ScrollView ref="sv"
  scrollEventThrottle={16}
  onScroll={this.handleScroll}
  onContentSizeChange={this.handleSize}
>
  {content}
</ScrollView>

If someone made something smoother, let us know!

Antoine
  • 5,504
  • 5
  • 33
  • 54
  • 1
    thanks and I think you're right, `although it's not very smooth, it does the job`, for the use case of mine, I pull down to load previous page content, the `handleSize` actually fires after the content has been rendered. So the user experience is user sees the top item and then be brought back to the original position where he was. This is really not good, but couldn't find a better approach, so I take yours. Thank you. – LiuWenbin_NO. Mar 29 '18 at 08:16
  • @LiuWenbin_NO. did u find any better approach? – Zeeshan Ahmad Khalil Apr 12 '21 at 09:57
  • I juat made `animated:true` so that it doesn't look like a glitch – Zeeshan Ahmad Khalil Apr 12 '21 at 10:00
  • @ZeeshanAhmadKhalil good work around. But how can it be done better? Smooth like scrolling a whatsapp chat to the top? – Yannick Schröder Sep 15 '21 at 12:30
  • @YannickSchröder use `FlatList` instead of `scrollview` – Zeeshan Ahmad Khalil Sep 16 '21 at 10:45
  • const [dheight, setHeight] = useState({}); const scroll = useRef(null) const onScroll = ({nativeEvent}) =>{ if(nativeEvent.contentOffset.y > 1){ setHeight(nativeEvent.contentSize.height) } } const handleSize = (width, height) => { if (dheight > 0) { const position = height - dheight scroll.current.scrollTo({x: 0, y: position, animated: false}) } } this work for me. i use this for chat box. this work append new data top. – saqib Feb 16 '22 at 19:02
1

More elegant sulotion:

<ScrollView
    ref={(ref => this.scrollViewRef = ref)}
    onScroll={event => { this.yOffset = event.nativeEvent.contentOffset.y }}
    onContentSizeChange={(contentWidth, contentHeight) => { this.scrollViewRef.scrollTo({ x: 0, y: this.yOffset, animated: false }) }}>
Idan
  • 3,604
  • 1
  • 28
  • 33