PagerSnapHelper 中的从到页面更改了侦听器

aks*_*t23 3 android android-support-library android-recyclerview pagersnaphelper

我正在PagerSnapHelper水平使用RecyclerView以实现类似行为的视图寻呼机。

final PagerSnapHelper pagerSnapHelper = new PagerSnapHelper(); pagerSnapHelper.attachToRecyclerView(recyclerView);

它工作得很好,但我希望能够在用户向任一方向更改页面时获得回调。所以像,onSwipeLeft/onSwipeRight回调。

我尝试使用findTargetSnapPositionin PagerSnapHelper,但这只会给我targetIndex而不是当前索引。我尝试过这样的事情,但它并不是一直有效。

@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
    final int targetPos = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);

    final View currentView = findSnapView(layoutManager);
    final int currentPos = layoutManager.getPosition(currentView);

    if (currentPos < targetPos) {
        callback.onSwipeRight();
    } else if (currentPos > targetPos) {
        callback.onSwipeLeft();
    }

    return targetPos;
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来实现这一目标并始终有效?谢谢!

Tre*_*urm 16

更新2
!!重要的提示 !!
如果您以编程方式调用scrollTo()并使用SnapPagerScrollListenerwith ON_SETTLEDonScrollStateChanged则不会被调用。所以旧的捕捉位置不会更新。WIP,将在我修复后立即更新课程。

更新

原始类在通知第一个布局时存在一些问题。现在它仅在项目位置从第一次变为RecyclerView.NO_POSITION其他位置时触发。

为了进一步扩展到仅在用户手势上忽略/触发,因此非编程调用scrollTo(),请注意,在编程调用的情况下onScrolled()会被触发dx == 0 and dy == 0

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


用法:
只需将 SnapPagerScrollListener 的实例添加到您的 RecyclerView

your_recycler_view.addOnScrollListener(new SnapPagerScrollListener(your_snap_helper, SnapPagerScrollListener.ON_SCROLL/ON_SETTLED, true/false, your_on_changed_listener));
Run Code Online (Sandbox Code Playgroud)


Type属性用于定义何时应触发回调。

  1. ON_SCROLL:用于在新视图/页面通过中间时立即通知回调
  2. ON_SETTLED:用于在 RecyclerViews 状态为 后通知回调SCROLL_STATE_IDLE。我使用该模式仅在滚动稳定后触发 API 调用。