ScrollView에 대한 docs를 읽다가 첫 줄에서부터 막혀버렸다.
Component that wraps platform ScrollView while providing integration with touch locking "responder" system.
저 문장에서 responder가 뭔데?
그래서 일단 responder에 대한 지식부터 습득하고 가기로 했다.
Gesture Responder System(제스쳐 응답자 시스템)은 앱에서 일어나는 제스쳐들의 라이프싸이클을 관리해주는 시스템이다. 사용자의 터치 제스쳐는 다양한 모양으로 일어날 수 있다. 예를 들어, 앱에서 일어나는 터치가 스크롤링 동작인지, 위젯을 슬라이딩 하는건지, 탭하는건지 등의 동작을 구별해야 한다. 이것은 터치가 일어나는 동안에도 바뀔 수 있다. 혹은 동시에 여러 터치가 일어날 수도 있다.
터치 응답자 시스템은 이런 터치 상호작용에 대해 컴포넌트가 (그 컴포넌트의 부모나 자식 컴포넌트에 대한 정보 없이) 적절히 협의(?)를 볼 수 있도록 해줘야 한다.
앱 사용감을 좋게 하기 위해선 각 액션들은 다음 특성을 가지고 있어야 한다.
위의 두 기능이 사용자가 앱을 사용할 때 더 편안함을 느낄 수 있게 해준다. (미리 수행 될 동작에 대한 정보를 보여주거나 취소할 수 있게 해줌으로써 실수를 방지할 수 있게 해주기 때문에)
응답자 시스템은 사용하기엔 좀 복잡할 수 있다. 그래서 React Native에선 '탭 가능해야하는' 것들을 위해 추상적인 Touchable 구현체를 제공한다. 이 구현체는 응답 시스템을 사용하고, 우리가 탭 상호작용에 대해 declarative하게 구성할 수 있게 해준다. 버튼이나 링크를 사용할 부분에서 <TouchableHighlight>을 사용하면 된다.
정확한 협상 메소드들을 구현해줌으로써 뷰는 '터치 응답자'가 될 수 있다. 뷰가 응답자가 되길 원하는지 물어보는 메소드 두 가지가 있다.
View.props.onStartShouldSetResponder: (evt) => true
: 이 뷰가 터치가 시작될 때 응답자가 되길 원하는가?View.props.onMoveShouldSetResponder: (evt) => true
: 뷰가 응답자가 아닐 경우에 터치 움직임이 일어나는 모든 순간마다 불리는 메소드이다. 이 뷰가 터치에 대한 책임을 '주장'하길 워하는가? (번역 참..)만약 뷰가 true를 리턴하면서 응답자가 되길 원한다면, 다음 중 하나가 일어나게 된다.
View.props.onResponderGrant: (evt) => {}
: 뷰는 이제 터치 이벤트에 대해 반응하고 있다. 하이라이팅을 통해 유저에게 어떤 일이 일어나고있는지 보여줄 때이다.View.props.onResponderReject: (evt) => {}
: 다른 무언가가 응답자이고 계속 그것이 응답자일 상태이다.만약 뷰가 응답중이라면, 다음 handler들이 불리게 된다.
View.props.onResponderMove: (evt) => {}
: 유저가 손가락을 움직이고 있다.View.props.onResponderRelease: (evt) => {}
: 'touchUp'이라고도 하는 터치가 끝나는 시점에 불린다.View.props.onResponderTerminationRequest: (evt) => true
: 다른 무언가가 응답자가 되길 원한다. 이 뷰는 응답자를 놓아줄 것인가? 만약 true를 리턴하면 놓아주게 된다.View.props.onResponderTerminate: (evt) => {}
: 뷰에 있던 응답자가 다른곳으로 가져가졌다. onResponderTerminationRequest 콜 이후에 다른 뷰로부터 가져가졌을 수도 있고, OS에 의해 강제로 가져가졌을 수 있다(iOS의 컨트롤센터나 알림센터에 의해 발생한다).evt
는 다음과 같은 형식의 종합적인 터치 이벤트이다.
nativeEvent
onStartShouldSetResponder와 onMoveShouldSetResponder는 가장 깊은 노드가 불린 곳 부터 버블링패턴으로 불린다. 이것은 여러 개의 뷰들이 *ShouldSetResponder
핸들러에 대해 true를 리턴했을 땐 가장 깊은 레벨의 컴포넌트가 응답자가 된다는 것을 의미한다. 이것이 대부분의 경우에 바람직한 상태이다. 모든 control들과 button들을 사용가능하게 만들어주기 때문이다.
그러나, 가끔 부모 뷰가 응답자가 되길 바랄 때도 있다. 이것은 capture phase를 사용해서 컨트롤할 수 있다. 응답자 시스템이 가장 깊은 컴포넌트로부터 버블링 되기 전에, 단계를 캡쳐해서 on*ShouldSetResponderCapture
이벤트를 발생시킨다. 그러니까 만약 부모 뷰가 자식이 터치의 시작시점에 응답자가 되는 것을 막고 싶을 때, true를 반환해주는 onStartShouldSetResponderCapture 핸들러를 갖고 있으면 된다.
View.props.onStartShouldSetResponderCapture: (evt) => true
View.props.onMoveShouldSetResponderCapture: (evt) => true
더 높은 레벨의 제스쳐 상호작용을 원한다면 PanResponder를 보기를..(이건 나중에 봐야지)
Ref: https://reactnative.dev/docs/gesture-responder-system#panresponder