关于RecyclerView实现瀑布流,上下滑动时item之间互换位置的问题

  最近项目需求,需要RecyclerView实现瀑布流。在用 StaggeredGridLayoutManager 完成瀑布流的过程中发现一个问题:它并不像pullToRefresh 那样是稳定的list,而是item之间频繁交换位置,有时候甚至会出现第一列和第二列完全互换的情况。

  我去搜索相关的问题,并没有人非常深入的去写这个控件,都是一些基础的用法。好吧,那只能自食其力,看源码喽。。。

 源码中 StaggeredGridLayoutManager 的解释中有这样一段话:

Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps,StaggeredGridLayoutManager can offset spans independently or move items between spans. You can control this behavior via {@link #setGapStrategy(int)}.

大概意思就是说 Staggered grid可能会有一定间距的布局边缘,为了避免这个问题StaggeredGridLayoutManager提供了解决这个问题的方法。即通过setGapStrategy(int)进行设置。

 /**
     * Does not do anything to hide gaps.
     */
    public static final int GAP_HANDLING_NONE = 0;


    @Deprecated
    public static final int GAP_HANDLING_LAZY = 1;


    /**
     * When scroll state is changed to {@link RecyclerView#SCROLL_STATE_IDLE}, StaggeredGrid will
     * check if there are gaps in the because of full span items. If it finds, it will re-layout
     * and move items to correct positions with animations.
     * <p>
     * For example, if LayoutManager ends up with the following layout due to adapter changes:
     * <pre>
     * AAA
     * _BC
     * DDD
     * </pre>
     * <p>
     * It will animate to the following state:
     * <pre>
     * AAA
     * BC_
     * DDD
     * </pre>
     */
    public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;

  大概意思是:GAP_HANDLING_NONE不为隐藏布局边缘差距做任何处理。

 GAP_HANDLING_LAZY 已经过期的变量。

GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS  通过item之间互换位置重新调整布局。

当我设置了layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);之后,发现item之间互换位置的情况解决了,但是却出现了从下往上滑动的时候,第一行的图片距离顶端有一定的空白区域。

问题出现只能继续解决,等我看了3遍源码,确实毫无头绪的时候就大胆试了一下,可能能解决这个问题的办法, 就在recycleView.addOnScrollListener的 onScrollStateChanged()方法中调用了staggeredGridLayoutManagerlayoutManager.invalidateSpanAssignments()。这样虽然完全符合了需求,item之间不会调换位置,从下往上滑动的时候,第一行的图片距离顶端无空白区域。但是又认真的看到源码中对此方法的注释,总是会觉得有点不妥当。

 /**
     * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items.
     * <p>
     * If you need to cancel current assignments, you can call this method which will clear all
     * assignments and request a new layout.
     */
    public void invalidateSpanAssignments() {
        mLazySpanLookup.clear();
        requestLayout();
    } 

解决方案:

recycleView.addOnScrollListener的onScrollStateChanged()的方法中调用staggeredGridLayoutManagerlayoutManager.invalidateSpanAssignments()。

有更好思路的小伙伴请指导

















猜你喜欢

转载自blog.csdn.net/sinat_21693123/article/details/50317399