获取“反应本机”中 ScrollView 的当前滚动位置

是否有可能获得当前的滚动位置,或 <ScrollView>组件的当前页面在反应本机?

比如:

<ScrollView
horizontal={true}
pagingEnabled={true}
onScrollAnimationEnd={() => {
// get this scrollview's current page or x/y scroll position
}}>
this.state.data.map(function(e, i) {
<ImageCt key={i}></ImageCt>
})
</ScrollView>
244964 次浏览

我相信 contentOffset会给你一个包含左上角滚动偏移量的对象:

Http://facebook.github.io/react-native/docs/scrollview.html#contentoffset

试试看。

<ScrollView onScroll={this.handleScroll} />

然后:

handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},

在另一个上下文中,假设您还想实现分页 指示器,你会想要进一步这样做:

<ScrollView
onScroll={Animated.event([{ nativeEvent: { contentOffset: { x:
scrollX } } }], {listener: (event) => handleScroll(event)})}
scrollEventThrottle={16}
>
...some content
</ScrollView>

其中 scrollX 将是一个动画值,您可以使用它进行分页,并且 handleScroll 函数可以采用以下形式:

  const handleScroll = (event) => {
const positionX = event.nativeEvent.contentOffset.x;
const positionY = event.nativeEvent.contentOffset.y;
};

Brad Oyler 的回答是正确的。但你们只能参加一个活动。如果你需要不断更新滚动位置,你应该设置 scrollEventThrottle道具,像这样:

<ScrollView onScroll={this.handleScroll} scrollEventThrottle={16} >
<Text>
Be like water my friend …
</Text>
</ScrollView>

事件处理程序:

handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},

请注意,您可能会遇到性能问题。相应地调整油门。16楼是最新的。只有一个。

至于页面,我正在开发一个高阶组件,它基本上使用上述方法来完成这项工作。它实际上只需要一点时间,当你下来到微妙的,如初始布局和内容的变化。我不会声称自己做得“正确”,但在某种意义上,我会考虑正确的答案,使用组件仔细而一致地完成这项工作。

看到: 本机页面反应滚动视图。我会很喜欢反馈,即使是我做的都是错的!

如果您希望简单地获取当前位置(例如,当某个按钮被按下时) ,而不是在用户滚动时跟踪它,那么调用 onScroll侦听器将导致性能问题。目前,获得当前滚动位置的最佳方法是使用 反应-本机-调用包。有一个例子可以说明这个问题,但是这个包做了很多其他的事情。

点击这里阅读。 Https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

要得到滚动结束后的 x/y 值,最简单的方法可能是:

<ScrollView
horizontal={true}
pagingEnabled={true}
onMomentumScrollEnd={(event) => {
// scroll animation ended
console.log(e.nativeEvent.contentOffset.x);
console.log(e.nativeEvent.contentOffset.y);
}}>
...content
</ScrollView>

免责声明: 以下内容主要是我自己在 React Native0.50中实验的结果。ScrollView文档目前缺少下面介绍的许多信息; 例如,onScrollEndDrag完全没有文档。由于这里的一切都依赖于非法行为,很遗憾,我不能保证一年甚至一个月后这些信息仍然是正确的。

此外,下面的所有内容都假设一个纯粹的垂直滚动视图,其 偏移量是我们感兴趣的; 如果需要的话,翻译成 X偏移量对于读者来说是一个很容易的练习。


ScrollView上的各种事件处理程序采用 event,并让您通过 event.nativeEvent.contentOffset.y获得当前滚动位置。其中一些处理程序在 Android 和 iOS 之间的行为略有不同,详见下文。

onScroll

在 Android 上

当用户滚动时触发每一帧,当用户放开滚动视图后滚动视图滑动时触发每一帧,当滚动视图停止时触发最后一帧,以及当滚动视图的偏移量因为帧的变化而变化时触发每一帧(例如由于从横向到纵向的旋转)。

在 iOS 上

在用户拖动或滚动视图滑动时触发,触发频率由 scrollEventThrottle确定,在 scrollEventThrottle={16}时每帧最多触发一次。如果用户释放滚动视图,当它有足够的动量滑行时,onScroll处理程序也会在滑行后停止时触发。但是,如果用户拖动,然后释放滚动视图,而它是静止的,onScroll没有保证为最后的位置触发,除非 scrollEventThrottle已设置为 onScroll触发每帧滚动。

设置 scrollEventThrottle={16}的性能成本可以通过将其设置为更大的数字来降低。但是,这意味着 onScroll不会触发每一帧。

onMomentumScrollEnd

当滚动视图滑动后停止时触发。如果用户在滚动视图处于静止状态时释放滚动视图,则该视图根本不会触发。

onScrollEndDrag

当用户停止拖动滚动视图时触发-不管滚动视图是静止的还是开始滑动。


考虑到这些行为上的差异,跟踪补偿的最佳方法取决于你的具体情况。在最复杂的情况下(你需要支持 Android 和 iOS,包括处理由于旋转导致的 ScrollView帧的变化,你不想接受在 Android 上从设置 scrollEventThrottle到16的性能损失) ,你还需要在滚动视图中处理对 内容的变化,那真是一团糟。

最简单的情况是,如果你只需要处理 Android; 只需使用 onScroll:

<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>

另外,为了支持 iOS,如果你很乐意每帧都触发 onScroll处理程序,并接受它对性能的影响,而 如果你不需要处理帧变化,那么它只是稍微复杂一点:

<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>

为了减少 iOS 上的性能开销,同时保证我们记录滚动视图设置的任何位置,我们可以增加 scrollEventThrottle,并额外提供一个 onScrollEndDrag处理程序:

<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>

但是如果我们想要处理帧的变化(例如,因为我们允许设备旋转,改变滚动视图的帧的可用高度)和/或内容的变化,那么我们必须额外实现 onContentSizeChangeonLayout来跟踪滚动视图的帧及其内容的高度,从而不断计算 最大值可能的偏移量,并推断偏移量何时由于帧或内容大小的变化而自动减少:

<ScrollView
onLayout={event => {
this.frameHeight = event.nativeEvent.layout.height;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onContentSizeChange={(contentWidth, contentHeight) => {
this.contentHeight = contentHeight;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
scrollEventThrottle={160}
>

是啊,太可怕了。我也不是100% 肯定它总是工作正确的情况下,您 同时改变的框架和内容的滚动视图的大小。但这是我能想到的最好的了,在 这个特性是在框架内部添加的之前,我认为这是任何人能做到的最好的了。

这就是如何最终获得当前滚动位置实时从视图。所有我正在做的是使用在滚动事件侦听器和 scrollEventThrottle。然后我传递它作为一个事件来处理我制作的滚动函数和更新我的道具。

 export default class Anim extends React.Component {
constructor(props) {
super(props);
this.state = {
yPos: 0,
};
}


handleScroll(event){
this.setState({
yPos : event.nativeEvent.contentOffset.y,
})
}


render() {
return (
<ScrollView onScroll={this.handleScroll.bind(this)} scrollEventThrottle={16} />
)
}
}

上面的答案告诉如何获得位置使用不同的 API,onScrollonMomentumScrollEnd等; 如果你想知道页面索引,你可以计算它使用偏移值。

 <ScrollView
pagingEnabled={true}
onMomentumScrollEnd={this._onMomentumScrollEnd}>
{pages}
</ScrollView>


_onMomentumScrollEnd = ({ nativeEvent }: any) => {
// the current offset, {x: number, y: number}
const position = nativeEvent.contentOffset;
// page index
const index = Math.round(nativeEvent.contentOffset.x / PAGE_WIDTH);


if (index !== this.state.currentIndex) {
// onPageDidChanged
}
};

enter image description here

在 iOS 中,ScrollView 与可见区域的关系如下: The picture comes from https://www.objc.io/issues/3-views/scroll-view/

档号: https://www.objc.io/issues/3-views/scroll-view/

使用 onScroll进入无限循环。可以使用 onMomentumScrollEndonScrollEndDrag代替

 <ScrollView style=\{\{ height: hp('70%'), width: '100%' }} showsVerticalScrollIndicator={false}
ref={myRef}


// for getting scrollView offset ->


onScroll={(event => setOffset(event.nativeEvent.contentOffset.y))}


// for giving scrollView offset ->


onContentSizeChange={() =>
myRef.current.scrollTo({
x: 0,
y: Offset
})
}
// pagingEnabled={true}
// scrollEventThrottle={16}
>

< ScrollView

ShowsVerticalScrollIndicator = { false }

Ref = { myRef }

OnScroll = {(event = > setOffset (event.nativeEvent.contentOffset.y))}

OnContentSizeChange = {() = >

ScrollTo ({

x: 0,


y: Offset

})

}