web-dev-qa-db-ja.com

React NativeのScrollViewの現在のスクロール位置を取得します

現在のスクロール位置、またはReact Nativeの<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>
86
Sang

やってみて。

<ScrollView onScroll={this.handleScroll} />

その後:

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

免責事項:以下は、主にReact Native 0.50での私自身の実験の結果です。 ScrollView documentation には、現在、以下で説明する多くの情報がありません。たとえば、onScrollEndDragは完全に文書化されていません。ここではすべてが文書化されていない動作に依存しているため、残念ながら、この情報が今から1年または1か月後にも正しいままであるという約束はできません。

また、以下のすべては、関心のある y オフセットを持つ純粋に垂直なスクロールビューを想定しています。 x オフセットへの変換は、必要に応じて、読者にとって簡単な練習になることを願っています。


ScrollViewのさまざまなイベントハンドラーはeventを受け取り、event.nativeEvent.contentOffset.yを介して現在のスクロール位置を取得できます。これらのハンドラーの一部は、AndroidとiOSの間で動作がわずかに異なります(以下で詳しく説明します)。

onScroll

Androidで

ユーザーがスクロールしている間、すべてのフレーム、ユーザーがリリースした後にスクロールビューが滑っている間、スクロールビューが静止する最終フレーム、およびフレームの結果としてスクロールビューのオフセットが変更されるたびに発生します。変更(例えば、横から縦への回転による)。

IOSで

ユーザーがドラッグしている間、またはスクロールビューが滑っている間に、 scrollEventThrottle で決定される一定の頻度で、scrollEventThrottle={16}のときにフレームごとに最大1回発生します。 ユーザーがスクロールするのに十分な勢いがあるときにスクロールビューを離すと、onScrollハンドラーは、グライド後の静止時にも起動します。ただし、ユーザーが静止している間にスクロールビューをドラッグしてから離すと、onScrollがすべてのフレームで起動するようにscrollEventThrottleが設定されていない限り、onScroll not スクロール。

scrollEventThrottle={16}の設定にはパフォーマンスコストがありますが、これを大きく設定することで削減できます。ただし、これはonScrollがすべてのフレームを起動するわけではないことを意味します。

onMomentumScrollEnd

グライド後にスクロールビューが停止したときに発生します。ユーザーがスクロールしないように静止しているときにユーザーがスクロールビューを離した場合、まったく起動しません。

onScrollEndDrag

ユーザーがスクロールビューのドラッグを停止すると、スクロールビューが静止したままであるか、滑空し始めたかにかかわらず発生します。


これらの動作の違いを考えると、オフセットを追跡する最善の方法は、正確な状況に依存します。最も複雑な場合(AndroidおよびiOSをサポートする必要があります。これには、ScrollViewのフレームの回転による変更を処理する必要があり、AndroidのscrollEventThrottleの設定によるパフォーマンスの低下を受け入れたくない場合) 16)スクロールビューで content への変更も処理する必要がある場合、それはまさに混乱です。

最も単純なケースは、Androidのみを処理する必要がある場合です。 onScrollを使用するだけです:

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

さらにiOSをサポートするには、 if フレームごとにonScrollハンドラーを起動し、そのパフォーマンスへの影響を受け入れて、 if youフレームの変更を処理する必要はありません、それはほんの少し複雑です:

<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 スクロールビューのフレームとそのコンテンツの両方の高さを追跡し、 maximum 可能なオフセットを継続的に計算し、オフセットがいつになるかを推測しますフレームまたはコンテンツサイズの変更により自動的に縮小されます。

<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%確実ではありません。しかし、それは私が考え出すことができる最高のものであり、 この機能はフレームワーク自体に追加されます になるまで、これは誰でもできる最高のものだと思います。

37
Mark Amery

Brad Oylerの答えは正しい。ただし、受け取るイベントは1つだけです。スクロール位置の継続的な更新を取得する必要がある場合は、次のように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 1つだけ。

17
cutemachine

ユーザーがスクロールするたびに追跡するのではなく、単に現在の位置を取得したい場合(ボタンが押された場合など)、onScrollリスナーを呼び出すとパフォーマンスの問題が発生します。現在、単純に現在のスクロール位置を取得する最もパフォーマンスの高い方法は、 react-native-invoke パッケージを使用することです。この正確な例はありますが、パッケージは他にも複数のことを行います。

ここでそれについて読んでください。 https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

6
Teodors

元の質問が要求していたときにスクロールが終了した後に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>
2
j0n

ページに関しては、基本的に上記のメソッドを使用して正確にこれを行う高次コンポーネントに取り組んでいます。実際には、最初のレイアウトやコンテンツの変更などの微妙な問題に取り掛かるのに少し時間がかかります。私はそれを「正しく」行ったと主張しませんが、ある意味では、これを注意深く一貫して行うコンポーネントを使用するための正しい答えを考えます。

react-native-paged-scroll-view を参照してください。たとえそれがすべて間違っていたとしても、フィードバックを歓迎します!

0
user657199

contentOffsetは、左上のスクロールオフセットを含むオブジェクトを提供すると信じています。

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

0
Colin Ramsay

これが、現在のスクロール位置をビューからライブで取得する方法です。私がしているのは、on scrollイベントリスナーと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