Is it possible to keep a ScrollView scrolled to the bottom?

前端 未结 16 1265
误落风尘
误落风尘 2020-12-04 17:13

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

相关标签:
16条回答
  • 2020-12-04 17:49

    Try setting the contentOffset property of the scroll view to the current height of the content.

    To accomplish what you need you could do this as part of the onScroll event. However this may make for a bad user experience so it may prove more user-friendly to only do this when a new message is appended.

    0 讨论(0)
  • 2020-12-04 17:50

    This method is a little bit hacky but I couldn't find a better way

    1. First add a ref to your ScrollView.
    2. Second add a dummy View before closing your ScrollView tag
    3. Get the y position of that dummy View
    4. Whenever you want to scroll to bottom scroll to the position of the dummy View

    var footerY; //Y position of the dummy view
    render() {    
        return (
          <View>
              <ScrollView 
              ref='_scrollView'>
                // This is where all the things that you want to display in the scroll view goes
                
                // Below is the dummy View
                <View onLayout={(e)=> {
                  footerY = e.nativeEvent.layout.y;
                  }}/>
              </ScrollView>
                  
              //Below is the button to scroll to the bottom    
              <TouchableHighlight
                onPress={() => { this.refs._scrollView.scrollTo(footerY); }}>
                <Text>Scroll to Bottom</Text>
              </TouchableHighlight>
            
          </View>
        );
      }

    0 讨论(0)
  • 2020-12-04 17:50

    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 (
          <ScrollView
            style={Styles.container}
            ref="scrollView"
            onContentSizeChange={(w, h) => {
              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;
            }}
          >
            <FlatList
              data={this.props.messages}
              renderItem={({ item }) => (
                <ChatMessage
                  text={item.text}
                  sender={item.sender}
                  time={item.time}
                  username={this.props.username}
                />
              )}
              keyExtractor={(item, index) => index.toString()}
            />
          </ScrollView>
        );
      }
    }
    
    0 讨论(0)
  • 2020-12-04 17:54

    try this solution

    xcode 10.0

    RN: 56.0.0

    <ScrollView ref="scrollView"
                 onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width
    
    0 讨论(0)
  • 2020-12-04 17:55

    Actually @Aniruddha answer doesn't worked for me because I'm using "react-native": "0.59.8" and this.scrollView.root.scrollToEnd also is undefined

    but I figured it out and this works this.scrollView.scrollResponderScrollToEnd({animated: true});

    If you are using 0.59.8 this will work OR if you are using later version and this works for you. please add versions in this answer so others wont get trouble.

    Full Code here

    <ScrollView
        ref={ref => this.scrollView = ref}
        onContentSizeChange={(contentWidth, contentHeight)=>{        
            this.scrollView.scrollResponderScrollToEnd({animated: true});
        }}>
    </ScrollView>
    
    0 讨论(0)
  • 2020-12-04 17:57

    I guess it is too late to answer but I got one hack! If you use FlatList you can enable inverted property which falls back to setting transform scale to -1 (which is acceptable for other list components like ScrollView ...) . When you render your FlatList with data it always will be on the bottom!

    0 讨论(0)
提交回复
热议问题