Ответ 1
Try.
<ScrollView onScroll={this.handleScroll} />
И затем:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},
Возможно ли получить текущую позицию прокрутки или текущую страницу компонента <ScrollView>
в React Native?
Так что-то вроде:
<ScrollView
horizontal={true}
pagingEnabled={true}
onScrollAnimationEnd={() => {
// get this scrollview current page or x/y scroll position
}}>
this.state.data.map(function(e, i) {
<ImageCt key={i}></ImageCt>
})
</ScrollView>
Try.
<ScrollView onScroll={this.handleScroll} />
И затем:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.y);
},
Отказ от ответственности: то, что следует, в первую очередь является результатом моих собственных экспериментов в React Native 0.50. В документации ScrollView
в настоящее время отсутствует большая часть информации, приведенной ниже; например, onScrollEndDrag
полностью недокументирован. Поскольку все здесь опирается на недокументированное поведение, я, к сожалению, не могу обещать, что эта информация останется правильной в течение года или даже через месяц.
Кроме того, все нижеследующее предполагает чисто вертикальное scrollview, у которого нас интересует смещение y; перевод на х смещения, если это необходимо, - это, без сомнения, легкое упражнение для читателя.
Различные обработчики событий в ScrollView
принимают event
и позволяют получить текущую позицию прокрутки через event.nativeEvent.contentOffset.y
. Некоторые из этих обработчиков имеют немного отличающееся поведение между Android и iOS, как описано ниже.
onScroll
Запускает каждый кадр, пока пользователь прокручивается, на каждом кадре, пока вид прокрутки скользит после того, как пользователь отпускает его, на последнем кадре, когда представление прокрутки останавливается, а также всякий раз, когда сдвиг вида прокрутки изменяется в результате его кадра (например, из-за поворота от пейзажа к портрету).
Пожары во время перетаскивания пользователя или пока режим прокрутки скользит, на определенной частоте определяется scrollEventThrottle
и не более одного раза за кадр, если scrollEventThrottle={16}
. Если пользователь отпускает вид прокрутки, пока он имеет достаточный импульс для скольжения, обработчик onScroll
также срабатывает, когда дело доходит до отдыха после скольжения. Однако, если пользователь перетаскивает, а затем отпускает вид прокрутки, пока она находится в неподвижном состоянии, onScroll
не гарантируется огонь для конечного положения, если scrollEventThrottle
не установлен таким образом, что onScroll
запускает каждый кадр прокруткой.
Для установки scrollEventThrottle={16}
существует стоимость исполнения, которая может быть уменьшена путем установки ее на большее число. Однако это означает, что onScroll
не будет onScroll
каждый кадр.
onMomentumScrollEnd
Пожары, когда просмотр прокрутки останавливается после скольжения. Не срабатывает вообще, если пользователь отпускает вид прокрутки, пока он неподвижен, так что он не скользит.
onScrollEndDrag
Пожары, когда пользователь останавливает перетаскивание прокрутки - независимо от того, остается ли просмотр прокрутки неподвижным или начинает скользить.
Учитывая эти различия в поведении, лучший способ отслеживать смещение зависит от ваших конкретных обстоятельств. В самом сложном случае (вам необходимо поддерживать Android и iOS, включая обработку изменений в кадре ScrollView
из-за вращения, и вы не хотите, чтобы scrollEventThrottle
производительности на Android от установки scrollEventThrottle
до 16), и вам нужно обрабатывать изменения в содержании в представлении прокрутки тоже, тогда это правильный проклятый беспорядок.
Самый простой случай: если вам нужно только обрабатывать Android; просто используйте onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Чтобы дополнительно поддерживать iOS, если вы с удовольствием onScroll
обработчик 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
, например:
<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
Чтобы получить 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. Хотелось бы получить обратную связь, даже если бы я сделал это неправильно!
Так получилось, что текущая позиция прокрутки в прямом эфире отображается. Все, что я делаю, это использовать прослушиватель событий прокрутки и 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, onScroll
, onMomentumScrollEnd
и т. Д.; Если вы хотите узнать индекс страницы, вы можете рассчитать его, используя значение смещения.
<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
}
};
Я считаю, что 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);
}