RecyclerView StaggeredGridLayoutManager瀑布流 添加Header

·  阅读 1325

可以通过StaggeredGridLayoutManager.LayoutParams的setFullSpan()方法来实现,继承recyclerView.Adapter 重写onViewAttachedToWindow方法:

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
    super.onViewAttachedToWindow(holder)
    val lp: ViewGroup.LayoutParams = holder.itemView.layoutParams
    if (lp is StaggeredGridLayoutManager.LayoutParams) {
        //根据viewType判断是否是占满一行
        if (isFullSpan(holder.itemViewType)) {
            lp.isFullSpan = true
            holder.itemView.layoutParams = lp
        } else {
            lp.isFullSpan = false
            holder.itemView.layoutParams = lp
        }
    }
}

override fun getItemViewType(position: Int): Int {
    val item = list[position]
    return if (item is BannerBean) {//banner
        ITEM_BANNER_HEADER
    } else if(item is OtherHeaderBean){//其他的header
        ITEM_OTHER_HEADER
    }else{
        ITEM_NORMAL//瀑布流item
    }
}

//判断是否占满一行
fun isFullSpan(viewType: Int)=viewType != ITEM_NORMAL
复制代码

瀑布流滑动出现跳动问题,是由于ViewHolder的回收机制,item重新绘制,导致的跳动,先拿到item的尺寸就行了,就可以避免这些问题。

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val item = list[position]
    when(holder.itemViewType){
        ITEM_BANNER -> (holder as BannerHolder).bind(item as BannerBean)//banner
        ITEM_OTHER_HEADER -> (holder as OtherHeaderHolder).bind(item as OtherHeaderBean)//其他的header
        else -> (holder as NormalHolder).bind(mRecyclerView,item as ImageBean)//瀑布流item
    }
}
复制代码

在瀑布流的NormalHolder的bind方法中设置好item的高度就行了,ImageView的宽度就是屏幕宽度-间距后除以spanCount,然后拿到图片的宽高比就可以得到ImageView的高度了。

fun bind(recyclerView: RecyclerView,imageBean : ImageBean){
    val manager: RecyclerView.LayoutManager? = recyclerView.getLayoutManager()
    if (manager is StaggeredGridLayoutManager) {
        val screenWidth = getScreenWidth(itemView.getContext())
        //(屏幕宽度-间距)/2 就是图片的宽度 ,当然这里的spanCount是2
        val width = (screenWidth - Utils.convertDpToPixel(54f))/2
        val lp: ViewGroup.LayoutParams = thumbIv.getLayoutParams()
        lp.width = width.toInt()
        //宽度*比例就得到高度,这里事先拿到图片宽高的比例
        lp.height = (width*imageBean.ratio).toInt()

        imageView.setLayoutParams(lp)
    }
    ...
}
复制代码

最后就是item直接间距的问题,如果UI给的效果图是左边的间距加右边的间距等于中间的间距,那就用常规的配置就行

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpaceItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.left = space;
        outRect.top = space;
        outRect.right = space;
        outRect.bottom = space;
    }
}
复制代码

如果是这种,左边item到左边是20dp,左右item中间的间隔也是20dp,右边item到右边是20dp,这种怎么办?

第一种方式设置recyclerView 的magin或者padding,设置为10dp,然后space也为10dp就行了。

第二种方式就是通过StaggeredGridLayoutManager.LayoutParams里的getSpanIndex()来判断这个item是左边的还是右边的。

public class StaggeredGridItemDecoration extends RecyclerView.ItemDecoration {

    //瀑布流的viewType类型
    private int staggeredGridViewType = 0;

    //间距
    private int space;
    
    public StaggeredGridItemDecoration(int staggeredGridViewType, int space) {
        this.staggeredGridViewType = staggeredGridViewType;
        this.space = space;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        RecyclerView.Adapter adapter = parent.getAdapter();
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (adapter==null || layoutManager==null){
            return;
        }
        int position = parent.getChildAdapterPosition(view);
        int viewType = adapter.getItemViewType(position);

        if(viewType == staggeredGridViewType){
            if (layoutManager instanceof StaggeredGridLayoutManager){
                int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
                int spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
                if (spanCount==2 && spanIndex != GridLayoutManager.LayoutParams.INVALID_SPAN_ID) {
                    if (spanIndex % 2 == 0) {
                        //这个是左边item
                        outRect.left = space;
                        outRect.right = space/2;
                    } else {
                        //这个是右边item
                        outRect.left = space/2;
                        outRect.right = space;
                    }
                    outRect.bottom = space;
                }
            }
        }
    }
}
复制代码
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改