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 오후
읽어주셔서 감사합니다 🙂