在React Native中滚动ScrollView到底部

9
我希望能找到一种编程方式,能够自动滚动到scrollView的底部。在查看了ScrollView的源代码后,我意识到了scrollTo方法,但是我似乎找不到测量scrollView内容大小的方法。
在寻找过程中,我发现this这个github问题提到了“UIManager.measureX方法的使用”,以此来测量内容大小。然而,在多次搜索源代码后,我似乎无法找到这些方法的使用位置。
请问有人能指点我正确的方向吗?
5个回答

14

它相当隐蔽,我偶然发现了源代码。

你可以像这样尝试:

要求:

var RCTUIManager = require('NativeModules').UIManager;

渲染:

<ScrollView ref = {component=>{this._scrollView=component;}}>
</ScrollView>

事件:

someEvent: function() {
  RCTUIManager.measure(this._scrollView.getInnerViewNode(), (...data)=>{console.log(data)});
}

从数据中,您可以获取高度为data的第四个元素的滚动视图的内容大小。当然,您也可以从中获得内容偏移量。有关详细信息,请查看RCTUIMananger.m的源代码。

当您使用getInnerViewNode时,您可以获得ScrollView内部视图的框架。如果您想获取ScrollView的框架,则应使用React.findNodeHandle(this._scrollView),而ScrollView的框架并不总是等于其内部视图的框架。


(更新)

如果您想用callback替换(...data)=>{console.log(data)},您应该像这样使用:

RCTUIManager.measure(this._scrollView.getInnerViewNode(), callback.bind(this));

谢谢回复。我尝试了你说的,但是数据参数总是返回0(零),而不是一个对象(或数组)。有什么想法吗? 我想我已经找到了你所说的源代码(https://github.com/facebook/react-native/blob/master/React/Modules/RCTUIManager.m)。measure的第一个参数似乎是一个reactTag,但我不太确定该标记指的是什么。 - coldbuffet
好的,谢谢你的帮助,现在我能够接收到scrollView内容的高度了,但是似乎还有另一个问题。每当我在 RCTUIManager.measure 的回调函数中引用 'this' 时,都会出现空指针错误。无论我是调用 this._scrollView 还是 this.someOtherMethod 都会出现这种情况。我做错了什么吗? - coldbuffet
你的回调函数在哪里?你是否已经将 ref 添加到 ScrollView 中了? - KChen
已经将ref添加到滚动视图中,因为我得到了正确的滚动视图内容高度。回调函数如下: RCTUIManager.measure(this._scrollView.getInnerViewNode(), (...data)=>{ console.log(data); this._scrollView.scrollTo(0, 0); //error here });然而,在尝试一段时间后,我发现这样做: RCTUIManager.measure(this._scrollView.getInnerViewNode(), this.someMethodUsingThisKeyword);不会抛出空错误。我猜测当使用匿名函数时,我没有对'this'的引用?您能解释一下这种行为吗?感谢您的帮助! - coldbuffet
你是否使用了类似 var callback = ...callback 回调函数? - KChen
显示剩余3条评论

2

1
有更好的方法来实现这个。简单来说:
使用 ListView 来渲染聊天记录。
<ListView
  ref="list"
  ...

使用renderFooter向列表添加页脚,使用onLayout保存其y位置。页脚不必呈现任何可见内容,只需一个空的View即可。您要找的是列表底部的位置。
renderFooter={() => {
  return <View onLayout={(e)=> {
    this.footerY = e.nativeEvent.layout.y;
  }}/>
}},

ListView本身上添加一个onLayout处理程序,保存列表的height
onLayout={(e)=>{
  this.listHeight = e.nativeEvent.layout.height;
}}

有了这两个信息,您可以这样滚动到列表底部:

if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
  var scrollDistance = this.listHeight - this.footerY;
  var scrollResponder = this.refs.list.getScrollResponder();
  scrollResponder.scrollWithoutAnimationTo(-scrollDistance);
}

你滚动到底部的频率取决于你的行为和需求。

GiftedMessenger是一个这样的例子。


1

虽然RCTUIManager.measure()可以通过引用提取数据数组的第四个元素来工作,但在使用ScrollView时,使用以下方法更为合适(且更容易):

参考链接:https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange

onContentSizeChange={( contentWidth, contentHeight ) => {
    this._contentHeight = contentHeight
}}

当内部子组件完成布局并发生变化时,此事件将触发。这对我很有效,我建议使用这种支持的方法来确定内容边界。


1
<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})
    }}>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接