Получить текущую позицию прокрутки ScrollView в React Native
можно ли получить текущую позицию прокрутки или текущую страницу <ScrollView>
компонент в React Native?
что-то вроде:
<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>
8 ответов
попробовать.
<ScrollView onScroll={this.handleScroll} />
и затем:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},
отказ от ответственности: то, что следует, в первую очередь является результатом моих собственных экспериментов в React Native 0.50. The ScrollView
документация в настоящее время отсутствует большая часть информации, описанной ниже; например onScrollEndDrag
совершенно без документов. Поскольку все здесь зависит от недокументированного поведения, я, к сожалению, не могу обещать, что эта информация останется верной через год или даже месяц.
кроме того, все ниже предполагает чисто вертикальный scrollview чей y смещение, которое нас интересует; перевод на x смещения, если это необходимо, надеюсь, легкое упражнение для читателя.
различные обработчики событий на ScrollView
взять event
и позволяют получить текущую позицию прокрутки через event.nativeEvent.contentOffset.y
. Некоторые из этих обработчиков имеют различное поведение между Android и iOS, как описано ниже.
onScroll
на Android
запускает каждый кадр во время прокрутки пользователя, на каждом кадре, когда вид прокрутки скользит после того, как пользователь отпускает его, на последнем кадре, когда вид прокрутки останавливается, а также всякий раз, когда смещение вида прокрутки изменяется в результате изменения его кадра (например, из-за поворота с ландшафта на портрет).
на iOS
срабатывает при перетаскивании пользователя или при скольжении вида прокрутки с определенной частотой, определяемой scrollEventThrottle
и не более одного раза за кадр, когда scrollEventThrottle={16}
. если пользователь выпускает вид прокрутки, пока он имеет достаточно импульса для скольжения,onScroll
обработчик также срабатывает, когда дело доходит до отдыха после катания. Однако, если пользователь перетаскивает, а затем освобождает вид прокрутки, пока он неподвижен,onScroll
is не гарантированный огонь для окончательной позиции, если 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}
>
но если мы хотим обрабатывать изменения кадра (например, потому что мы разрешаем поворачивать устройство, изменяя доступную высоту для кадра прокрутки) и / или изменения содержимого, то мы должны дополнительно реализовать оба onContentSizeChange
и onLayout
чтобы отслеживать высоту как кадра прокрутки, так и его содержимого, и тем самым постоянно вычислять максимум возможное смещение и вывод, когда смещение было автоматически уменьшено из-за изменения размера кадра или содержимого:
<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
prop, вот так:
<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 предоставляет вам обновления. 0 только один.
Если вы хотите просто получить текущую позицию (например, когда какая-то кнопка нажата), а не отслеживать ее всякий раз, когда пользователь прокручивает, а затем вызывает onScroll
слушатель будет вызывать проблемы с производительностью. В настоящее время самый эффективный способ просто получить текущую позицию прокрутки-использовать react-native-invoke. Существует пример для этой точной вещи, но пакет делает несколько других вещей.
читать об этом здесь. https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd
Я считаю contentOffset
даст вам объект, содержащий смещение прокрутки в левом верхнем углу:
http://facebook.github.io/react-native/docs/scrollview.html#contentoffset
Это должно работать как для Android, так и для iOS (протестировано на Android):
<ScrollView ref='myScrollView'>
<Text>Blah</Text>
</ScrollView>
...
getOffset() {
console.log(this.refs.myScrollView.scrollProperties.offset);
}
чтобы получить 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-native-paged-scroll-view. Хотел бы обратную связь, даже если это что я все сделал неправильно!