ViewPager만들기
ViewPager2와 방식은 비슷하지만, 아직 정식 릴리즈가 나오지 않았습니다.
기존에 RecyclerView가 구현이 되어있다면 PagerSnapHelper만 추가하면 된다.
MyAdapter adapter = ... recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); // PagerSnapHelper 추가 PagerSnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(recyclerView);
Indicator 추가하기
RecyclerView에는 ItemDecoration을 이용해서 Indicator를 그릴수 있습니다.
저는 LinePagerIndicatorDecoration 참고해서 그려보았습니다.
recyclerView.addItemDecoration(new LinePagerIndicatorDecoration());
SnapPagerScrollListener 추가하기
ViewPager와는 다르게 RecyclerView는 페이지 변경 리스너가 없으므로, 스크롤 리스너를 이용하여 페이지 변경 이벤트를 받아야합니다. SnapPagerScrollListener는 스택오버플로의 TreyWurm의 답변을 참고했습니다.
public class SnapPagerScrollListener extends RecyclerView.OnScrollListener { // Constants public static final int ON_SCROLL = 0; public static final int ON_SETTLED = 1; @IntDef({ON_SCROLL, ON_SETTLED}) public @interface Type { } public interface OnChangeListener { void onSnapped(int position); } // Properties private final PagerSnapHelper snapHelper; private final int type; private final boolean notifyOnInit; private final OnChangeListener listener; private int snapPosition; // Constructor public SnapPagerScrollListener(PagerSnapHelper snapHelper, @Type int type, boolean notifyOnInit, OnChangeListener listener) { this.snapHelper = snapHelper; this.type = type; this.notifyOnInit = notifyOnInit; this.listener = listener; this.snapPosition = RecyclerView.NO_POSITION; } // Methods @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if ((type == ON_SCROLL) || !hasItemPosition()) { notifyListenerIfNeeded(getSnapPosition(recyclerView)); } } @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (type == ON_SETTLED && newState == RecyclerView.SCROLL_STATE_IDLE) { notifyListenerIfNeeded(getSnapPosition(recyclerView)); } } private int getSnapPosition(RecyclerView recyclerView) { RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager == null) { return RecyclerView.NO_POSITION; } View snapView = snapHelper.findSnapView(layoutManager); if (snapView == null) { return RecyclerView.NO_POSITION; } return layoutManager.getPosition(snapView); } private void notifyListenerIfNeeded(int newSnapPosition) { if (snapPosition != newSnapPosition) { if (notifyOnInit && !hasItemPosition()) { listener.onSnapped(newSnapPosition); } else if (hasItemPosition()) { listener.onSnapped(newSnapPosition); } snapPosition = newSnapPosition; } } private boolean hasItemPosition() { return snapPosition != RecyclerView.NO_POSITION; } }
SnapPagerScrollListener 클래스를 만들었으니 이제 RecyclerView에 스크롤 리스너를 추가 해보겠습니다.
SnapPagerScrollListener listener = new SnapPagerScrollListener( pagerSnapHelper, SnapPagerScrollListener.ON_SCROLL, true, new SnapPagerScrollListener.OnChangeListener() { @Override public void onSnapped(int position) { //position 받아서 이벤트 처리 } } ); recyclerView.addOnScrollListener(listener);
Callback이 트리거 되는 시점을 조절하는 두가지 Type이 있습니다.
- ON_SCROLL : 스크롤이 될때 콜백을 받고 싶다면 이 타입을 사용
- ON_SETTLED : RecyclerView의 State가 SCROLL_STATE_IDLE일때, 즉 페이지가 변경되고 완전히 멈출때 이벤콜백을 받고 싶다면 이 타입을 사용합니다.
2개의 댓글
미소 · 2022년 4월 11일 7:00 오후
SnapPageListener 정리해주셔서 잘 썼습니다. 감사합니다.!!
Charlezz · 2022년 4월 12일 5:12 오후
읽어주셔서 감사합니다 🙂