development

React Native에서 ScrollView의 현재 스크롤 위치 가져 오기

big-blog 2020. 8. 29. 12:24
반응형

React Native에서 ScrollView의 현재 스크롤 위치 가져 오기


<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>

시험.

<ScrollView onScroll={this.handleScroll} />

그리고:

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

면책 조항 : 다음은 주로 React Native 0.50에서 직접 실험 한 결과입니다. ScrollView문서는 현재 아래에 적용되는 많은 정보가 누락; 예를 들어 onScrollEndDrag완전히 문서화되지 않았습니다. 여기에있는 모든 것은 문서화되지 않은 행동에 의존하기 때문에 안타깝게도이 정보가 지금부터 1 년 또는 심지어 한 달 후에도 정확한 상태로 유지 될 것이라고 약속 할 수 없습니다.

또한 아래의 모든 것은 y 오프셋에 관심이 있는 순전히 수직 스크롤 뷰를 가정합니다 . 필요한 경우 x 오프셋으로 변환하는 것은 독자에게 쉬운 연습이되기를 바랍니다.


ScrollView테이크 에 대한 다양한 이벤트 핸들러를 사용하면 event통해 현재 스크롤 위치를 가져올 수 있습니다 event.nativeEvent.contentOffset.y. 이러한 핸들러 중 일부는 아래에 설명 된대로 Android와 iOS간에 약간 다른 동작을합니다.

onScroll

Android에서

사용자가 스크롤하는 동안 모든 프레임, 사용자가 놓은 후 스크롤 뷰가 글라이딩하는 동안 모든 프레임, 스크롤 뷰가 정지 될 때 마지막 프레임에서, 그리고 프레임의 결과로 스크롤 뷰의 오프셋이 변경 될 때마다 발생합니다. 변경 (예 : 가로에서 세로로의 회전으로 인해).

iOS에서

화재는 사용자가 드래그하거나 스크롤보기 글라이딩 동안 몇몇 주파수에 의해 결정되는 반면 scrollEventThrottle때 프레임 당 많아야 한 번 scrollEventThrottle={16}. 경우 사용자가 스크롤 뷰를 해제 해 글라이드에 충분한 힘을 가지고 동안 onScroll핸들러는 화재 때 글라이딩 후 휴식을 제공합니다. 사용자가 드래그 한 후이 정지 상태에서 스크롤 뷰를 해제하는 경우에는, onScroll되어 있지 않는 한 최종 위치에 대한 화재 보장 scrollEventThrottle같은 설정되었는지 onScroll화재 스크롤의 모든 프레임.

scrollEventThrottle={16}더 큰 숫자로 설정하여 줄일 수있는 설정 성능 비용 이 있습니다. 그러나 이것은 onScroll모든 프레임을 발사하지는 않는다는 것을 의미합니다 .

onMomentumScrollEnd

글라이딩 후 스크롤 뷰가 멈출 때 발생합니다. 사용자가 움직이지 않도록 고정되어있는 동안 스크롤 뷰를 놓으면 전혀 실행되지 않습니다.

onScrollEndDrag

사용자가 스크롤보기가 정지 된 상태로 있거나 글라이딩을 시작하는지 여부에 관계없이 스크롤보기 드래그를 중지하면 실행됩니다.


이러한 동작 차이를 고려할 때 오프셋을 추적하는 가장 좋은 방법은 정확한 상황에 따라 다릅니다. 가장 복잡한 경우 ( ScrollView회전으로 인한의 프레임 변경 처리를 포함하여 Android 및 iOS를 지원해야하며 설정 scrollEventThrottle에서 16 까지의 Android에서 성능 저하를 받아들이고 싶지 않음 ) 처리해야합니다. 스크롤 뷰 내용도 변경되면 엉망입니다.

가장 간단한 경우는 Android 만 처리해야하는 경우입니다. 그냥 사용하십시오 onScroll:

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

또한 아이폰 OS를 지원하기 위해, 만약 당신이하고있는 화재 행복 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}
>

But if we want to handle frame changes (e.g. because we allow the device to be rotated, changing the available height for the scroll view's frame) and/or content changes, then we must additionally implement both onContentSizeChange and onLayout to keep track of the height of both the scroll view's frame and its contents, and thereby continually calculate the maximum possible offset and infer when the offset has been automatically reduced due to a frame or content size change:

<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}
>

Yeah, it's pretty horrifying. I'm also not 100% certain that it'll always work right in cases where you simultaneously change the size of both the frame and content of the scroll view. But it's the best I can come up with, and until this feature gets added within the framework itself, I think this is the best that anyone can do.


Brad Oyler's answer is correct. But you will only receive one event. If you need to get constant updates of the scroll position, you should set the scrollEventThrottle prop, like so:

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

And the event handler:

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

Be aware that you might run into performance issues. Adjust the throttle accordingly. 16 gives you the most updates. 0 only one.


If you wish to simply get the current position (e.g. when some button is pressed) rather than tracking it whenever the user scrolls, then invoking an onScroll listener is going to cause performance issues. Currently the most performant way to simply get current scroll position is using react-native-invoke package. There is an example for this exact thing, but the package does multiple other things.

Read about it here. https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd


To get the x/y after scroll ended as the original questions was requesting, the easiest way is probably this:

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

As for the page, I'm working on a higher order component that uses basically the above methods to do exactly this. It actually takes just a bit of time when you get down to the subtleties like initial layout and content changes. I won't claim to have done it 'correctly', but in some sense I'd consider the correct answer to use component that does this carefully and consistently.

See: react-native-paged-scroll-view. Would love feedback, even if it's that I've done it all wrong!


This is how ended up getting the current scroll position live from the view. All I am doing is using the on scroll event listener and the scrollEventThrottle. I am then passing it as an event to handle scroll function I made and updating my props.

 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} />
    )
    }
    }

I believe contentOffset will give you an object containing the top-left scroll offset:

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

참고URL : https://stackoverflow.com/questions/29503252/get-current-scroll-position-of-scrollview-in-react-native

반응형