it-swarm.com.ru

Получить текущую позицию прокрутки 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>
86
Sang

Пытаться.

<ScrollView onScroll={this.handleScroll} />

А потом: 

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

Отказ от ответственности: то, что следует, является прежде всего результатом моих собственных экспериментов в React Native 0.50. В ScrollView документации в настоящее время отсутствует большая часть информации, представленной ниже; например, onScrollEndDrag полностью недокументирован. Поскольку все здесь основано на недокументированном поведении, я, к сожалению, не могу обещать, что эта информация останется верной через год или даже месяц.

Кроме того, все, что ниже, предполагает чисто вертикальное представление прокрутки, чье смещение y нас интересует; перевод в x смещений, если необходимо, надеюсь, будет легким упражнением для читателя.


Различные обработчики событий в ScrollView принимают event и позволяют вам получить текущую позицию прокрутки с помощью event.nativeEvent.contentOffset.y. Некоторые из этих обработчиков ведут себя немного по-разному в Android и iOS, как описано ниже.

onScroll

На андроид

Запускает каждый кадр, когда пользователь выполняет прокрутку, на каждом кадре, когда представление прокрутки скользит после того, как пользователь отпускает его, в последнем кадре, когда представление прокрутки останавливается, а также всякий раз, когда смещение представления прокрутки изменяется в результате его кадра. изменение (например, из-за поворота от пейзажа к портрету).

На iOS

Срабатывает, когда пользователь перетаскивает или когда вид прокрутки скользит, с некоторой частотой, определяемой scrollEventThrottle , и не более одного раза за кадр, когда scrollEventThrottle={16}. Если пользователь освобождает представление прокрутки, когда у него достаточно импульса для скольжения, обработчик onScroll также сработает, когда он остановится после скольжения. Однако, если пользователь перетаскивает, а затем освобождает представление прокрутки, пока оно находится в неподвижном состоянии, onScroll является not гарантированно сработает для конечной позиции, если только scrollEventThrottle не был установлен таким образом, что onScroll запускает каждый кадр прокрутки.

Установка scrollEventThrottle={16} приводит к снижению производительности, которую можно уменьшить, установив большее значение. Однако это означает, что onScroll не будет запускать каждый кадр.

onMomentumScrollEnd

Запускается, когда вид прокрутки останавливается после скольжения. Не срабатывает вообще, если пользователь отпускает представление прокрутки, пока оно неподвижно, так что оно не скользит.

onScrollEndDrag

Срабатывает, когда пользователь прекращает перетаскивать вид прокрутки - независимо от того, является ли вид прокрутки неподвижным или начинает скользить.


Учитывая эти различия в поведении, лучший способ отслеживать смещение зависит от ваших конкретных обстоятельств. В самом сложном случае (вам необходимо поддерживать Android и iOS, включая обработку изменений в кадре ScrollView из-за поворота, и вы не хотите принимать снижение производительности на Android от установки scrollEventThrottle до 16), и вам нужно обрабатывать изменения в content в представлении прокрутки тоже, тогда это чертовски беспорядок.

Самый простой случай, если вам нужно работать только с 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%, что это всегда будет работать правильно в тех случаях, когда вы одновременно изменяете размер как фрейма, так и содержимого представления прокрутки. Но это лучшее, что я могу придумать, и до тех пор, пока эта функция будет добавлена ​​в сам фреймворк , я думаю, что это лучшее, что может сделать любой.

30
Mark Amery

Ответ Брэда Ойлера верен. Но вы получите только одно событие. Если вам нужно постоянно обновлять позицию прокрутки, вы должны установить опцию 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 только один.

18
cutemachine

Если вы хотите просто получить текущую позицию (например, когда нажата какая-то кнопка), а не отслеживать ее всякий раз, когда пользователь выполняет прокрутку, то вызов слушателя onScroll вызовет проблемы с производительностью. В настоящее время наиболее эффективный способ просто получить текущую позицию прокрутки - это использовать Reaction-native-invoke package. Есть пример для этой точной вещи, но пакет делает много других вещей.

Прочтите об этом здесь . https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

6
Teodors

Чтобы получить х/у после того, как прокрутка закончилась в соответствии с первоначальными вопросами, самый простой способ, вероятно, заключается в следующем:

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

Что касается страницы, я работаю над компонентом более высокого порядка, который использует в основном вышеуказанные методы, чтобы сделать именно это. На самом деле это занимает немного времени, когда вы переходите к тонкостям, таким как первоначальный макет и изменения содержимого. Я не буду утверждать, что сделал это «правильно», но в некотором смысле я бы рассмотрел правильный ответ, чтобы использовать компонент, который делает это тщательно и последовательно.

Смотрите: response-native-paged-scroll-view . Очень хотелось бы получить обратную связь, даже если бы я все сделал неправильно!

0
user657199

Я полагаю, что contentOffset даст вам объект, содержащий верхнее левое смещение прокрутки:

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

0
Colin Ramsay

Вот как в итоге получилась текущая позиция прокрутки в реальном времени из вида. Все, что я делаю, это использую прослушиватель событий при прокрутке и 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} />
    )
    }
    }
0
Sabba Keynejad