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일때, 즉 페이지가 변경되고 완전히 멈출때 이벤콜백을 받고 싶다면 이 타입을 사용합니다.
카테고리: Java

2개의 댓글

미소 · 2022년 4월 11일 7:00 오후

SnapPageListener 정리해주셔서 잘 썼습니다. 감사합니다.!!

    Charlezz · 2022년 4월 12일 5:12 오후

    읽어주셔서 감사합니다 🙂

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.