控制 RecyclerView Item 停留位置(居中?左对齐?)

11,591 阅读2分钟
原文链接: mp.weixin.qq.com

在使用RecyclerView作为一个横向滑动控件时,有时对滑动后RecyclerView中的Item停留位置有要求,如希望Item居中等:

第一排为滑动后居中,第二排为滑动后左对齐


之前做这种需求需要自己去实现,在Support library 的24.2.0中增加了SnapHelper,可以满足我们的需求。

SnapHelper是一个抽象类,support library中只提供了一个继承类LinearSnapHelper ,可以使item居中。SnapHelper使用起来很简单:

SnapHelper snapHelper = new LinearSnapHelper();snapHelper.attachToRecyclerView(yourRecyclerView);

实现item 左对齐



LinearSnapHelper是居中操作,如何实现左对齐呢,我们可以继承LinearSnapHelper并覆盖其中的两个方法即可以实现:

1. calculateDistanceToFinalSnap

覆盖这个方法去设置目标View或者Container View滚动到指定的位置。当SnapHelper在fling结束时回调该方法去获取到达最终位置需要做的调整,即当recyclerview正常滑动结束后可能并不是在我们需要的位置,然后回调该方法,获取还需要调整的距离。

2. findSnapView

覆盖这个方法,可以设置最重需要调整的目标View。当SnapHelper需要开始snapping时回调该方法获取需要调整的target view。

我们看一下最中的实现代码:

public class StartSnapHelper extends LinearSnapHelper {


private OrientationHelper mVerticalHelper, mHorizontalHelper;

public StartSnapHelper() {

}

@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView)
        throws IllegalStateException {
    super.attachToRecyclerView(recyclerView);
}

@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,
                                          @NonNull View targetView) {
    int[] out = new int[2];

    if (layoutManager.canScrollHorizontally()) {
        out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
    } else {
        out[0] = 0;
    }

    if (layoutManager.canScrollVertically()) {
        out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager));
    } else {
        out[1] = 0;
    }
    return out;
}

@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {

    if (layoutManager instanceof LinearLayoutManager) {

        if (layoutManager.canScrollHorizontally()) {
            return getStartView(layoutManager, getHorizontalHelper(layoutManager));
        } else {
            return getStartView(layoutManager, getVerticalHelper(layoutManager));
        }
    }

    return super.findSnapView(layoutManager);
}

private int distanceToStart(View targetView, OrientationHelper helper) {
    return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
}

private View getStartView(RecyclerView.LayoutManager layoutManager,
                          OrientationHelper helper) {

    if (layoutManager instanceof LinearLayoutManager) {
        int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();

        boolean isLastItem = ((LinearLayoutManager) layoutManager)
                .findLastCompletelyVisibleItemPosition()
                == layoutManager.getItemCount() - 1;

        if (firstChild == RecyclerView.NO_POSITION || isLastItem) {
            return null;
        }

        View child = layoutManager.findViewByPosition(firstChild);

        if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2
                && helper.getDecoratedEnd(child) > 0) {
            return child;
        } else {
            if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition()
                    == layoutManager.getItemCount() - 1) {
                return null;
            } else {
                return layoutManager.findViewByPosition(firstChild + 1);
            }
        }
    }

    return super.findSnapView(layoutManager);
}

private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager) {
    if (mVerticalHelper == null) {
        mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
    }
    return mVerticalHelper;
}

private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {
    if (mHorizontalHelper == null) {
        mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
    }
    return mHorizontalHelper;
}
}

使用方法和LinearSnapHelper是一样的。

感谢阅读,贴一下完整demo地址 https://github.com/MindorksOpenSource/SnapHelperExample

欢迎关注公众号wutongke,了解更多移动开发前沿技术:


wutongke