如何滚动到React Native ListView的底部

iwo*_*ngu 37 react-native

我正在使用React Native编写应用程序.它有一个ListView显示项目列表.

当有新的项目可用时,我会在底部添加新项目.我想滚动到底部以ListView自动显示新项目.我怎样才能做到这一点?

jon*_*asb 10

作为本土做出反应都0.41 ListViewScrollViewscrollToEnd()方法.ListView的文件记录在https://facebook.github.io/react-native/docs/listview.html#scrolltoend

在渲染时,您需要使用a ref来存储对您的引用ListView:

<ListView
  dataSource={yourDataSource}
  renderRow={yourRenderingCallback}
  ref={listView => { this.listView = listView; }}
</ListView>
Run Code Online (Sandbox Code Playgroud)

然后,您可以调用this.listView.scrollToEnd()滚动到列表的底部.如果您希望每次ListView更改内容时(例如,添加内容时)都这样做,那么请在ListView's onContentSizeChangeprop回调中执行此操作,就像使用ScrollView.


Koh*_*ver 8

我解决了这个问题ScrollView.这是一个简单的例子:

class MessageList extends Component {
    componentDidUpdate() {
        let innerScrollView = this._scrollView.refs.InnerScrollView;
        let scrollView = this._scrollView.refs.ScrollView;

        requestAnimationFrame(() => {
            innerScrollView.measure((innerScrollViewX, innerScrollViewY, innerScrollViewWidth, innerScrollViewHeight) => {
                scrollView.measure((scrollViewX, scrollViewY, scrollViewWidth, scrollViewHeight) => {
                    var scrollTo = innerScrollViewHeight - scrollViewHeight + innerScrollViewY;

                    if (innerScrollViewHeight < scrollViewHeight) {
                        return;
                    }

                    this._scrollView.scrollTo(scrollTo);
                });
            });
        });
    }

    render() {
        return (
            <ScrollView ref={component => this._scrollView = component}>
                {this.props.messages.map((message, i) => {
                    return <Text key={i}>{message}</Text>;
                })}
            </ScrollView>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢@ccheever


Sat*_*ino 8

这个问题有一个非常简单的解决方案.您可以将ListView包装在Scrollview组件中.这将提供确定列表底部位置的所有必要方法.

首先包装listView

<ScrollView> 
  <MyListViewElement />
</ScrollView>
Run Code Online (Sandbox Code Playgroud)

然后使用返回组件(scrollView)高度的onLayout方法.并将其保存到州.

// add this method to the scrollView component
onLayout={ (e) => {

  // get the component measurements from the callbacks event
  const height = e.nativeEvent.layout.height

  // save the height of the scrollView component to the state
  this.setState({scrollViewHeight: height })
}}
Run Code Online (Sandbox Code Playgroud)

然后使用onContentSizeChange方法返回内部组件(listView)的高度.并将其保存到州.每次从列表中添加或删除元素或更改高度时都会发生这种情况.基本上每当有人向您的列表添加新消息时.

onContentSizeChange={ (contentWidth, contentHeight) => {

  // save the height of the content to the state when there’s a change to the list
  // this will trigger both on layout and any general change in height
  this.setState({listHeight: contentHeight })

}}
Run Code Online (Sandbox Code Playgroud)

要滚动,您需要在ScrollView中找到scrollTo方法.你可以通过在这样的状态下将它保存到ref来访问它.

<ScrollView
  ref={ (component) => this._scrollView = component } 
  …
  >
</ScrollView>
Run Code Online (Sandbox Code Playgroud)

现在,您拥有计算所需的一切,并触发滚动到列表底部.您可以选择在组件中的任何位置执行此操作,我会将其添加到组件中,componentDidUpdate()因此无论何时组件呈现它都会滚动到底部.

  componentDidUpdate(){
    // calculate the bottom
    const bottomOfList =  this.state.listHeight - this.state.scrollViewHeight

    // tell the scrollView component to scroll to it
    this.scrollView.scrollTo({ y: bottomOfList })   
 }
Run Code Online (Sandbox Code Playgroud)

就是这样.这就是ScrollView最终应该是这样的样子

<ScrollView
  ref={ (component) => this._scrollView = component }

  onContentSizeChange={ (contentWidth, contentHeight) => {
    this.setState({listHeight: contentHeight })
  }}    

  onLayout={ (e) => {
    const height = e.nativeEvent.layout.heigh
    this.setState({scrollViewHeight: height })
  }}
  > 
  <MyListViewElement />
</ScrollView>
Run Code Online (Sandbox Code Playgroud)

一个简单的方法我使用ListView并发现使用scrollView更容易做到这一点,为了简单起见,我推荐它.这是我的消息模块的直接副本,用于滚动到底部功能.希望能帮助到你.

class Messages extends Component {
  constructor(props){
    super(props)
    this.state = {
      listHeight: 0,
      scrollViewHeight: 0
    }
  }
  componentDidUpdate(){
    this.scrollToBottom()
  }
  scrollToBottom(){
    const bottomOfList =  this.state.listHeight - this.state.scrollViewHeight
    console.log('scrollToBottom');
    this.scrollView.scrollTo({ y: bottomOfList })
  }
  renderRow(message, index){
    return (
        <Message
          key={message.id}
          {...message}
        />
    );
  }
  render(){
    return(
      <ScrollView
        keyboardDismissMode="on-drag"
        onContentSizeChange={ (contentWidth, contentHeight) => {
          this.setState({listHeight: contentHeight })
        }}
        onLayout={ (e) => {
          const height = e.nativeEvent.layout.height
          this.setState({scrollViewHeight: height })
        }}
        ref={ (ref) => this.scrollView = ref }>
        {this.props.messages.map(  message =>  this.renderRow(message) )}
      </ScrollView>
    )
  }
}

export default Messages
Run Code Online (Sandbox Code Playgroud)


Dar*_*ius 7

我遇到了同样的问题,并提出了这个解决方案:

render()
{
    if("listHeight" in this.state && 
           "footerY" in this.state && 
               this.state.footerY > this.state.listHeight)
    {
        var scrollDistance = this.state.listHeight - this.state.footerY;
        this.refs.list.getScrollResponder().scrollTo(-scrollDistance);
    }

    return (
            <ListView ref="list"

                onLayout={(event) => {

                    var layout = event.nativeEvent.layout;

                    this.setState({
                        listHeight : layout.height
                    });

                }}
                renderFooter={() => {

                    return <View onLayout={(event)=>{

                        var layout = event.nativeEvent.layout;

                        this.setState({
                            footerY : layout.y
                        });

                    }}></View>
                }}
            />
    )
}
Run Code Online (Sandbox Code Playgroud)

基本上,我渲染一个空页脚,以确定列表底部的Y偏移量.从这里我可以根据列表容器高度导出到底部的滚动偏移量.

注意:最后一个if条件检查内容长度是否溢出列表高度,并且只检查它是否滚动.您是否需要这取决于您的设计!

希望这个解决方案可以帮助其他人处于相同的位置

FWIW我不喜欢在另一个答案中讨论的InvertibleScrollView插件,因为它对整个列表和每个列表项进行了比例转换..这听起来很贵!


laz*_*wei 3

请查看: https: //github.com/650Industries/react-native-invertible-scroll-view

该组件反转原始滚动视图。因此,当新项目到达时,它会自动滚动到底部。

不过,请注意两点

  1. 您的“数据数组”也需要恢复。也就是说,应该是

    [new_item, old_item]
    
    Run Code Online (Sandbox Code Playgroud)

    任何新到达的项目都应插入到最前面。

  2. 尽管他们ListView在自述文件示例中使用了此插件,但在使用此插件时仍然存在一些缺陷ListView。相反,我建议您只使用ScrollView,它效果很好。

反向滚动视图的示例:

var MessageList = React.createClass({
  propTypes: {
    messages: React.PropTypes.array,
  },

  renderRow(message) {
    return <Text>{message.sender.username} : {message.content}</Text>;
  },

  render() {
    return (
      <InvertibleScrollView
        onScroll={(e) => console.log(e.nativeEvent.contentOffset.y)}
        scrollEventThrottle={200}
        renderScrollView={
          (props) => <InvertibleScrollView {...props} inverted />
        }>
        {_.map(this.props.messages, this.renderRow)}
      </InvertibleScrollView>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)