2026년 상식닷컴 선정 식당 & 카페 리스트
최근에 오픈한 호텔을 찾는다면 살펴보세요

ViewPager에서 다른 뷰와 동시에 스크롤하는 방법은?

_____
Q1: ViewPager에서 다른 뷰(예: ScrollView, RecyclerView)와 동시에 스크롤을 하려면 어떻게 해야 하나요?
A1: ViewPager가 자신의 스크롤 제스처를 가로 스와이프로 처리하는 동안, 내부의 다른 뷰(예: ScrollView)는 세로 스크롤을 처리하도록 이벤트를 분리해야 합니다. 이를 위해서는 터치 이벤트를 적절히 조작하여 겹치는 스크롤 동작을 명확히 구분해야 합니다.

---

Q2: 터치 이벤트 분리 방법은 무엇인가요?
A2: ViewPager의 `onInterceptTouchEvent(MotionEvent ev)` 메서드를 오버라이드하여, 스크롤 방향과 터치 이동량을 판단 후 특정 방향(예: 수평 스와이프)일 때만 이벤트를 가로채고, 그렇지 않으면 자식 뷰가 해당 이벤트를 처리하도록 할 수 있습니다. 즉, 세로 움직임이 커서 수직 스크롤하는 경우 부모인 ViewPager가 이벤트를 가로채지 않도록 하는 방식입니다.

---

Q3: 직접 구현할 때 참고할 만한 코드 패턴이 있나요?
A3: 네, 다음과 같은 방식으로 구현합니다.

```java
public class CustomViewPager extends ViewPager {
private float startX, startY;
private boolean isVpDragger; // ViewPager가 스크롤 중인지

public CustomViewPager(Context context) {
super(context);
}

public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = ev.getX();
startY = ev.getY();
isVpDragger = false;
super.onInterceptTouchEvent(ev); // 반드시 호출해서 초기화
break;
case MotionEvent.ACTION_MOVE:
float endX = ev.getX();
float endY = ev.getY();
float distanceX = Math.abs(endX - startX);
float distanceY = Math.abs(endY - startY);
if (distanceX > distanceY && distanceX > touchSlop) {
// 수평 이동이 크면 ViewPager가 스크롤하도록 허용
isVpDragger = true;
return super.onInterceptTouchEvent(ev);
} else if (distanceY > distanceX) {
// 수직 이동이 크면, 이벤트를 자식에게 넘겨서 세로 스크롤 처리
return false;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isVpDragger = false;
break;
}
return super.onInterceptTouchEvent(ev);
}
}
```
위 코드는 ViewPager가 수평 스크롤에만 반응하고, 세로 스크롤 시에는 이벤트를 가로채지 않도록 조절하는 예입니다. `touchSlop`은 시스템에서 제공하는 최소 터치 이동 거리입니다.

---

Q4: 이런 로직을 적용하면 어떤 문제가 해결되나요?
A4: 내부 스크롤 뷰(ScrollView, RecyclerView 등)의 세로 스크롤과 ViewPager의 수평 스와이프가 충돌하는 문제를 해결할 수 있어, 사용자가 자연스럽게 수직과 수평 방향 스크롤을 모두 사용할 수 있게 됩니다.

---

Q5: 만약 NestedScrollView 등과 함께 쓴다면?
A5: Android Design Support Library의 `NestedScrollView`와 `ViewPager2`를 함께 쓰면 기본적으로 상호 협조하는 스크롤 이벤트 처리가 더 원활합니다. 하지만 여전히 수평과 수직 스크롤 방향 판별이 필요하면, 위와 같은 터치 이벤트 조작이나 `requestDisallowInterceptTouchEvent(true)` 호출을 적절히 활용해야 합니다.

---

Q6: 다른 라이브러리나 방법이 있나요?
A6: 서드파티 라이브러리 중에는 복합 스크롤 처리를 지원하는 뷰페이저 커스텀이 많이 있습니다. 또한 AndroidX의 `ViewPager2`는 RecyclerView를 기반으로 구현되어 좀 더 유연한 스크롤 조작이 가능합니다. 가능하면 ViewPager 대신 ViewPager2 사용을 권장합니다.

---

요약:
- ViewPager가 수평 스와이프만 가로채고 세로 스크롤은 내부 뷰가 처리하도록 `onInterceptTouchEvent`를 커스텀한다.
- 수평/수직 이동량을 판단해 이벤트 전파를 조절한다.
- ViewPager2와 NestedScrollView 조합을 활용하면 복잡한 터치 처리가 쉬워진다.
- `requestDisallowInterceptTouchEvent(true)`를 자식 뷰에서 호출해 부모 뷰의 이벤트 가로채기를 제한하는 것도 효과적이다.
ViewPager에서 다른 뷰와 동시에 스크롤하는 방법은 매우 흥미로운 주제입니다.

이는 사용자 경험을 향상시키기 위해 여러 개의 뷰를 동기화해야 할 때 유용합니다.

여기에 대한 몇 가지 접근 방식을 안내하겠습니다.

1. ViewPager와 RecyclerView 연동하기 ViewPager와 RecyclerView를 함께 사용하여 동기화된 스크롤을 구현할 수 있습니다.

RecyclerView의 스크롤 이벤트를 감지하고 ViewPager의 페이지를 변경할 수 있습니다.

예시 코드: ```kotlin class CustomViewPager(context: Context) : ViewPager(context) { fun scrollToPosition(position: Int) { // 특정 포지션으로 스크롤하는 로직 구현 } } class MyActivity : AppCompatActivity() { private lateinit var viewPager: CustomViewPager private lateinit var recyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewPager = findViewById(R.id.viewPager) recyclerView = findViewById(R.id.recyclerView) // RecyclerView의 스크롤 리스너 설정 recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // RecyclerView의 스크롤에 따라 ViewPager 페이지 이동 val position = viewPager.currentItem viewPager.scrollToPosition(position) } }) } } ```

2. Viewpager의 페이지 변경 리스너 설정 ViewPager의 페이지가 변경될 때 다른 뷰를 동기화하는 방법입니다.

여기서 ViewPager의 페이지 변경 리스너를 사용하여 다른 뷰의 상태를 업데이트합니다.

예시 코드: ```kotlin viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { // 페이지가 스크롤되는 동안 다른 뷰 업데이트 } override fun onPageSelected(position: Int) { // 새로운 페이지가 선택되면 다른 뷰의 상태 업데이트 } override fun onPageScrollStateChanged(state: Int) { // 스크롤 상태 변경 시 처리 } }) ```

3. GestureDetector 사용하기 GestureDetector를 사용하여 사용자 제스처에 따라 ViewPager와 다른 뷰의 스크롤을 동시에 처리할 수 있습니다.

예시 코드: ```kotlin class MyActivity : AppCompatActivity() { private lateinit var viewPager: ViewPager private lateinit var someOtherView: View private val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean { viewPager.scrollBy(distanceX.toInt(), 0) // ViewPager의 X축으로 스크롤 // 다른 뷰의 스크롤 처리 someOtherView.scrollBy(distanceX.toInt(), 0) return true } }) override fun onTouchEvent(event: MotionEvent): Boolean { gestureDetector.onTouchEvent(event) return super.onTouchEvent(event) } } ```

4. Custom ViewPager 구현하기 Custom ViewPager를 만들어 `onTouchEvent`를 오버라이드하여 직접 스크롤 동작을 조정하고, 다른 뷰와의 동기화 로직을 추가할 수 있습니다.

주의사항 - 성능 : 동시에 여러 뷰를 스크롤할 경우 성능에 영향을 줄 수 있으니 최적화를 고려해야 합니다.

- 사용자 경험 : 사용자에게 혼란을 주지 않도록 스크롤 동작을 잘 설계하는 것이 중요합니다.

이와 같은 방식으로 ViewPager와 다른 뷰를 동기화하여 사용자의 경험을 극대화할 수 있습니다.

다양한 방법을 조합하여 원하는 기능을 구현하세요!
작성자: 정지민 [비회원] | 작성일자: 1년 전 2025-04-03 07:01:23
조회수: 122 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.