스크롤 뷰 외부의 제스처를 스크롤 뷰에 반영(Android/iOS)
동기
빈번한 유스 케이스가 아닐지도 모르지만, 때때로 아래 그림과 같이 화면보다 상당히 작은 스크롤 뷰를 보여주고 싶을 때가 있습니다 (개인적으로 여러 번 그러한 디자인을 구현 한 적이있었습니다) . 그러나 스와이프나 빵이라고 하는 움직임은 가로 방향으로 큰 움직임이므로, 스크롤의 제스처 자체는 화면 전체로부터 취하고 싶거나 합니다.
Android의 경우
GestureDetector
의 onScroll(MotionEvent, MotionEvent, Float, Float)
를 구현한 것에, 외부의 view 로 발생한 touch 이벤트를 포착시킵니다. 그리고 onScroll(...)
안에서 얻어진 횡방향 distance 를 스크롤 뷰에 반영합니다.
코드 예에서는, 스크롤 뷰라고 하는 것보다, ViewPager
를 이용한 경우를 이용합니다만, ScrollView
하지만 RecyclerView
하지만 기본적인 생각은 사용할 수 있다고 생각합니다.
아래의 구현 예는 Kotlin 코드입니다.
GestureDetector 초기화
private var isScrolling = false
private val panGestureDetector = GestureDetectorCompat(activity, object: GestureDetector.SimpleOnGestureListener() {
override fun onScroll(
e1: MotionEvent, e2: MotionEvent,
distanceX: Float, distanceY: Float
): Boolean {
// 1. ここに来るということは間違いなくスクロール中であるので、カスタムフラグを立てる。
isScrolling = true
// 2. もしまだ ViewPager に ドラッグを指示していなければ、ドラッグ開始を指示
if (view?.viewPager?.isFakeDragging() == false) {
view?.viewPager?.beginFakeDrag()
}
// 3. スクロールイベントと反対方向に ViewPager をドラッグ
view?.viewPager?.fakeDragBy(-distanceX)
return true
}
override fun onDown(e: MotionEvent?): Boolean {
// 4. onDown イベントをオーバーライドしておかないと、スクロールなど onDown から開始されるイベントを捕捉できないっぽい。
return true
}
})
View.OnTouchListener를 만들고 외부 뷰의 touch 이벤트를 잡습니다.
private val touchListner = object: View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
// 1. panGestureDetector が処理できるイベントに関しては panGestureDetector に任せる
if (panGestureDetector.onTouchEvent(event)) {
return true
}
// 2. ドラッグの後処理。ACTION_UP を受理したということはドラッグが終了したということ。
if (event?.getAction() == MotionEvent.ACTION_UP) {
if (isScrolling) {
if (view?.viewPager?.isFakeDragging() == true) {
// 2.1. ViewPager にドラッグの終了を指示して
view?.viewPager?.endFakeDrag()
}
// 2.2. カスタムフラグをリセット
isScrolling = false
}
}
return true
}
}
그리고는, touchListener
를 스크롤 이벤트를 포착하고 싶은 바깥쪽의 view
로 설정해 주는 것 뿐입니다.
view.setOnTouchListener(touchListner)
결과
스크롤 뷰는 파란 이마 속입니다만, 이마 밖을 스크롤해도 제대로 이마 안이 스크롤 합니다. 불행히도 100%라는 것은 아니고, 기린의 곳에서 한 번 공 흔들고 있습니다.
iOS의 경우
이 기사는, 일반적으로 이것이 쓰고 싶었던 느낌입니다만 ^^; iOS 는 이 거동을 매우 간단하게 쓸 수 있습니다. UIScrollView
의 스크롤은 UIPanGestureRecognizer
와 UISwipeGestureRecognizer
에 의해 관리됩니다. 그래서 이러한 GestureRecognizer 를 바깥 뷰에 올려 놓으면, 마치 이상하게, 마치 스크롤 뷰의 터치 영역이 바깥쪽까지 확장되어 있는 것처럼 움직입니다.
아래 코드 예제는 Swift로 작성되었습니다.
if let gestureRecognizers = scrollView.gestureRecognizers {
for gestureRecognizer in gestureRecognizers.makeIterator() {
if gestureRecognizer is UIPanGestureRecognizer || gestureRecognizer is UISwipeGestureRecognizer {
// 外側の view に GestureRecognizer を乗せる。
view.addGestureRecognizer(gestureRecognizer as UIGestureRecognizer)
}
}
}
결과
구조적으로 외부 제스처를 그대로 안에 전해지므로 거동 자체도 iOS 쪽이 원활합니다.
그건 그렇고,이 방법은 WWDC 2014 세션 235에서 소개되었습니다.
요약
화면에 작은 스크롤 뷰가 있고 외부에서 스와이프 제스처를 한 경우에도 스크롤을 하고 싶은 경우, iOS에서도 Android에서도 외부 제스처를 스크롤 뷰로 보내는 형태로 실현할 수 있습니다.
그러나 구조적으로 iOS는 압도적으로 쉽게 구현할 수 있습니다. 또, iOS 의 경우, UICollectionView
도 UIScrollView
를 계승하고 있기 때문에, 그쪽을 채용해도 완전히 같은 코드를 사용할 수 있는 안심감도 있습니다. Android의 경우 여기에서는 ViewPager
를 사용했지만 ScrollView
또는 RecyclerView
하지 마세요.
안드로이드를 할 생각은 전혀 없습니다만, iOS 에서 ViewPager
는 화면 컴퍼넌트의 핵심으로서, 매우 잘 디자인되고 있다고 하는 인상을 강하게 했습니다. (아니, 안드로이드의 이해가 부족할 뿐이라는 지적이 있으면 꼭 교수해 주세요)
Reference
이 문제에 관하여(스크롤 뷰 외부의 제스처를 스크롤 뷰에 반영(Android/iOS)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yfujiki/items/9654f823faa250563e87
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
GestureDetector
의 onScroll(MotionEvent, MotionEvent, Float, Float)
를 구현한 것에, 외부의 view 로 발생한 touch 이벤트를 포착시킵니다. 그리고 onScroll(...)
안에서 얻어진 횡방향 distance 를 스크롤 뷰에 반영합니다.코드 예에서는, 스크롤 뷰라고 하는 것보다,
ViewPager
를 이용한 경우를 이용합니다만, ScrollView
하지만 RecyclerView
하지만 기본적인 생각은 사용할 수 있다고 생각합니다.아래의 구현 예는 Kotlin 코드입니다.
GestureDetector 초기화
private var isScrolling = false
private val panGestureDetector = GestureDetectorCompat(activity, object: GestureDetector.SimpleOnGestureListener() {
override fun onScroll(
e1: MotionEvent, e2: MotionEvent,
distanceX: Float, distanceY: Float
): Boolean {
// 1. ここに来るということは間違いなくスクロール中であるので、カスタムフラグを立てる。
isScrolling = true
// 2. もしまだ ViewPager に ドラッグを指示していなければ、ドラッグ開始を指示
if (view?.viewPager?.isFakeDragging() == false) {
view?.viewPager?.beginFakeDrag()
}
// 3. スクロールイベントと反対方向に ViewPager をドラッグ
view?.viewPager?.fakeDragBy(-distanceX)
return true
}
override fun onDown(e: MotionEvent?): Boolean {
// 4. onDown イベントをオーバーライドしておかないと、スクロールなど onDown から開始されるイベントを捕捉できないっぽい。
return true
}
})
View.OnTouchListener를 만들고 외부 뷰의 touch 이벤트를 잡습니다.
private val touchListner = object: View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
// 1. panGestureDetector が処理できるイベントに関しては panGestureDetector に任せる
if (panGestureDetector.onTouchEvent(event)) {
return true
}
// 2. ドラッグの後処理。ACTION_UP を受理したということはドラッグが終了したということ。
if (event?.getAction() == MotionEvent.ACTION_UP) {
if (isScrolling) {
if (view?.viewPager?.isFakeDragging() == true) {
// 2.1. ViewPager にドラッグの終了を指示して
view?.viewPager?.endFakeDrag()
}
// 2.2. カスタムフラグをリセット
isScrolling = false
}
}
return true
}
}
그리고는,
touchListener
를 스크롤 이벤트를 포착하고 싶은 바깥쪽의 view
로 설정해 주는 것 뿐입니다. view.setOnTouchListener(touchListner)
결과
스크롤 뷰는 파란 이마 속입니다만, 이마 밖을 스크롤해도 제대로 이마 안이 스크롤 합니다. 불행히도 100%라는 것은 아니고, 기린의 곳에서 한 번 공 흔들고 있습니다.
iOS의 경우
이 기사는, 일반적으로 이것이 쓰고 싶었던 느낌입니다만 ^^; iOS 는 이 거동을 매우 간단하게 쓸 수 있습니다. UIScrollView
의 스크롤은 UIPanGestureRecognizer
와 UISwipeGestureRecognizer
에 의해 관리됩니다. 그래서 이러한 GestureRecognizer 를 바깥 뷰에 올려 놓으면, 마치 이상하게, 마치 스크롤 뷰의 터치 영역이 바깥쪽까지 확장되어 있는 것처럼 움직입니다.
아래 코드 예제는 Swift로 작성되었습니다.
if let gestureRecognizers = scrollView.gestureRecognizers {
for gestureRecognizer in gestureRecognizers.makeIterator() {
if gestureRecognizer is UIPanGestureRecognizer || gestureRecognizer is UISwipeGestureRecognizer {
// 外側の view に GestureRecognizer を乗せる。
view.addGestureRecognizer(gestureRecognizer as UIGestureRecognizer)
}
}
}
결과
구조적으로 외부 제스처를 그대로 안에 전해지므로 거동 자체도 iOS 쪽이 원활합니다.
그건 그렇고,이 방법은 WWDC 2014 세션 235에서 소개되었습니다.
요약
화면에 작은 스크롤 뷰가 있고 외부에서 스와이프 제스처를 한 경우에도 스크롤을 하고 싶은 경우, iOS에서도 Android에서도 외부 제스처를 스크롤 뷰로 보내는 형태로 실현할 수 있습니다.
그러나 구조적으로 iOS는 압도적으로 쉽게 구현할 수 있습니다. 또, iOS 의 경우, UICollectionView
도 UIScrollView
를 계승하고 있기 때문에, 그쪽을 채용해도 완전히 같은 코드를 사용할 수 있는 안심감도 있습니다. Android의 경우 여기에서는 ViewPager
를 사용했지만 ScrollView
또는 RecyclerView
하지 마세요.
안드로이드를 할 생각은 전혀 없습니다만, iOS 에서 ViewPager
는 화면 컴퍼넌트의 핵심으로서, 매우 잘 디자인되고 있다고 하는 인상을 강하게 했습니다. (아니, 안드로이드의 이해가 부족할 뿐이라는 지적이 있으면 꼭 교수해 주세요)
Reference
이 문제에 관하여(스크롤 뷰 외부의 제스처를 스크롤 뷰에 반영(Android/iOS)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yfujiki/items/9654f823faa250563e87
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
if let gestureRecognizers = scrollView.gestureRecognizers {
for gestureRecognizer in gestureRecognizers.makeIterator() {
if gestureRecognizer is UIPanGestureRecognizer || gestureRecognizer is UISwipeGestureRecognizer {
// 外側の view に GestureRecognizer を乗せる。
view.addGestureRecognizer(gestureRecognizer as UIGestureRecognizer)
}
}
}
화면에 작은 스크롤 뷰가 있고 외부에서 스와이프 제스처를 한 경우에도 스크롤을 하고 싶은 경우, iOS에서도 Android에서도 외부 제스처를 스크롤 뷰로 보내는 형태로 실현할 수 있습니다.
그러나 구조적으로 iOS는 압도적으로 쉽게 구현할 수 있습니다. 또, iOS 의 경우,
UICollectionView
도 UIScrollView
를 계승하고 있기 때문에, 그쪽을 채용해도 완전히 같은 코드를 사용할 수 있는 안심감도 있습니다. Android의 경우 여기에서는 ViewPager
를 사용했지만 ScrollView
또는 RecyclerView
하지 마세요.안드로이드를 할 생각은 전혀 없습니다만, iOS 에서
ViewPager
는 화면 컴퍼넌트의 핵심으로서, 매우 잘 디자인되고 있다고 하는 인상을 강하게 했습니다. (아니, 안드로이드의 이해가 부족할 뿐이라는 지적이 있으면 꼭 교수해 주세요)
Reference
이 문제에 관하여(스크롤 뷰 외부의 제스처를 스크롤 뷰에 반영(Android/iOS)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yfujiki/items/9654f823faa250563e87텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)