[ios] 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를 지원해야하며 Android에서 설정 scrollEventThrottle에서 16으로 의 성능 저하를 받아들이고 싶지 않음 ) 처리해야합니다. 스크롤 뷰 의 내용도 변경되면 엉망입니다.

가장 간단한 경우는 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}
>

우리가 (우리가 스크롤 뷰의 프레임에 사용 가능한 높이를 변경, 장치가 회전 할 수 있기 때문에 예를) 및 / 또는 내용 변경 프레임 변경을 처리하는 경우에, 우리는 또한 모두를 구현해야 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 % 확신하지는 않습니다 . 하지만 이것이 제가 생각할 수있는 최선의 방법이며, 이 기능이 프레임 워크 자체에 추가 될 때까지 누구나 할 수있는 최선이라고 생각합니다.


답변

Brad Oyler의 대답이 맞습니다. 단 하나의 이벤트 만 받게됩니다. 스크롤 위치를 지속적으로 업데이트해야하는 경우 다음 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>


답변

위의 답변은 다른 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
   }
 };

여기에 이미지 설명 입력

iOS에서 ScrollView와 가시 영역 간의 관계는 다음과 같습니다.
사진은 https://www.objc.io/issues/3-views/scroll-view/에서 가져온 것입니다.

참조 : https://www.objc.io/issues/3-views/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} />
    )
    }
    }