RecyclerView分组悬浮列表

转载自tuacy

RecyclerView分组悬浮列表

列表展示是开发过程中经常用到的功能,通常通过 ListView 或者 RecyclerView 控件来实现。在列表显示的过程中可能会碰到这样的需求:需要对列表进行分组,每个分组都有标题 item view 和内容 item view 而且希望列表在滑动的过程中每个分组的标题 item view 可以一直固定的列表的顶部。下面我们通过 RecyclerView 来实现这一需求。

在讲怎么实现之前先献上通过RecyclerView实现的效果图

LinearLayoutManager实现的效果
在这里插入图片描述

GridLayoutManager实现的效果,要固定在顶部的 item要占据整个一行
在这里插入图片描述

接下来就是实现过程了

我们知道 RecyclerView 给提供了一个RecyclerView.ItemDecoration 来给我们使用,这可是好东西呀。RecyclerView.ItemDecoration 从字面上来看是用来给 RecyclerView 里面每个 item 添加装饰用的(当然也可以给RecyclerView的整体添加装饰)。例如,你可以通过 RecyclerView.ItemDecoration 来给 RecyclerView 的每个 item 添加分割线、给每个 item 添加 padding 等等。这里我们通过 RecyclerView.ItemDecoration 来实现 RecyclerView 分组悬浮列表的功能。

我们先简单的看下RecyclerView.ItemDecoration里面几个函数:

/**
 * 可以通过重写这个函数给RecyclerView绘制任意合适的decorations(装饰)
 * 会在RecyclerView item绘制之前绘制。可以认为是绘制在RecyclerView的下面
 * 会在RecyclerView类的onDraw()里面调用
 */
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    onDraw(c, parent);
}

/**
 * deprecated掉的函数我们不管,忽视掉,不建议使用了
 */
@Deprecated
public void onDraw(Canvas c, RecyclerView parent) {
}

/**
 * 可以通过重写这个函数给RecyclerView绘制任意合适的decorations(装饰)
 * 会在RecyclerView item绘制之后绘制。可以认为是绘制在RecyclerView的上面(在上面在盖一层)
 * 会在RecyclerView类的super.draw()之后调用,
 */
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    onDrawOver(c, parent);
}

/**
 * deprecated掉的函数不建议使用了,忽视掉
 */
@Deprecated
public void onDrawOver(Canvas c, RecyclerView parent) {
}


/**
 * deprecated掉的函数不建议使用了,忽视掉
 */
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
    outRect.set(0, 0, 0, 0);
}

/**
 * 给RecyclerView item对应的每个view增加一些offsets(你可以这么认为item对应的view外面还有一层布局,给这个布局增加padding)
 */
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    getItemOffsets(outRect, ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent);
}

看到 ItemDecoration 提供到我们的就三个函数了:onDraw()、onDrawOver()、getItemOffsets()。getItemOffsets()函数会在 RecyclerView 里面每个子 view 测量的时候调用,可以用来给每个子 view 添加offset(间距)。onDraw()会在RecyclerView的onDraw()方法里面调用。onDrawOver()函数会在RecyclerView的draw()函数里面调用。关于onDraw()、onDrawOver()两个函数的区分咱们可以简单的认为onDraw()是在RecyclerView绘制内容的时候调用。onDrawOver()是在RecyclerView绘制完内容之后再调用,相当于可以在RecyclerView之上在绘制一层内容

通过对 RecyclerView.ItemDecoration 类的简单分析,再结合我们分组固定标题 View 的需求,我们是要把每个分组的标题 View 固定在顶部,恩,那肯定是在要绘制在RecyclerView层之上的吧,和RecyclerView.ItemDecoration里面的onDrawOver()函数正好对应上了。

接下来的事情就好办了

首先,既然有些标题是要固定的,那咱们一定要明确的知道哪些position位置对应的view是标题吧,只能通过adapter做文章了,所有我们就有了一个基础的PinnedHeaderAdapter,代码如下:

public abstract class PinnedHeaderAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

    /**
     * 判断该position对应的位置是要固定
     *
     * @param position adapter position
     * @return true or false
     */
    public abstract boolean isPinnedPosition(int position);

}

接下来,RecyclerView.ItemDecoration里面的onDrawOver()函数里面我们做好三件事情就好了:第一,找到当前界面要一直固定在顶部的 View、第二,把找到固定在顶部的 View 画在 RecyclerView 的顶部、第三,当将要到达顶部的标题 View 和已经画在顶部的 View 相遇的时候顶部 view 上移的问题。这三个问题实现起来也不复杂,所以这里我们就直接贴代码了,毕竟代码才是王道吗。

/**
 * 把要固定的View绘制在上层
 */
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    super.onDrawOver(c, parent, state);
    //确保是PinnedHeaderAdapter的adapter,确保有View
    if (parent.getAdapter() instanceof PinnedHeaderAdapter && parent.getChildCount() > 0) {
        PinnedHeaderAdapter adapter = (PinnedHeaderAdapter) parent.getAdapter();
        //找到要固定的pin view
        View firstView = parent.getChildAt(0);
        int firstAdapterPosition = parent.getChildAdapterPosition(firstView);
        int pinnedHeaderPosition = getPinnedHeaderViewPosition(firstAdapterPosition, adapter);
        if (pinnedHeaderPosition != -1) {
            RecyclerView.ViewHolder pinnedHeaderViewHolder = adapter.onCreateViewHolder(parent, adapter.getItemViewType(pinnedHeaderPosition));
            adapter.onBindViewHolder(pinnedHeaderViewHolder, pinnedHeaderPosition);
            //要固定的view
            View pinnedHeaderView = pinnedHeaderViewHolder.itemView;
            ensurePinnedHeaderViewLayout(pinnedHeaderView, parent);
            int sectionPinOffset = 0;
            for (int index = 0; index < parent.getChildCount(); index++) {
                if (adapter.isPinnedPosition(parent.getChildAdapterPosition(parent.getChildAt(index)))) {
                    View sectionView = parent.getChildAt(index);
                    int sectionTop = sectionView.getTop();
                    int pinViewHeight = pinnedHeaderView.getHeight();
                    if (sectionTop < pinViewHeight && sectionTop > 0) {
                        sectionPinOffset = sectionTop - pinViewHeight;
                    }
                }
            }
            int saveCount = c.save();
            c.translate(0, sectionPinOffset);
            c.clipRect(0, 0, parent.getWidth(), pinnedHeaderView.getMeasuredHeight());
            pinnedHeaderView.draw(c);
            c.restoreToCount(saveCount);
        }

    }
}

整个功能到这就结束了,是不是很简单。最后贡献上源码RecyclerPinnedHeader源码下载地址

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现RecyclerView悬浮吸顶效果,可以使用以下步骤: 1. 创建一个布局文件,包含两个部分:一个用于悬浮显示的视图,一个用于RecyclerView。 2. 在Activity或Fragment中,找到RecyclerView并设置布局管理器和适配器。 3. 创建一个自定义的RecyclerView.ItemDecoration类,用于绘制悬浮视图。 4. 在自定义的ItemDecoration类中,重写getItemOffsets()方法,在该方法中计算悬浮视图的高度,并将其应用到RecyclerView的第一个可见项之上。 5. 在自定义的ItemDecoration类中,重写onDraw()方法,在该方法中绘制悬浮视图。 6. 在Activity或Fragment中,为RecyclerView添加ItemDecoration。 下面是一个简单的示例代码: 1. 创建布局文件(例如:activity_main.xml): ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/floating_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Floating View" android:background="#FF0000" android:textColor="#FFFFFF" android:padding="16dp" android:visibility="gone" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/floating_view" /> </RelativeLayout> ``` 2. 在Activity或Fragment中,设置RecyclerView的布局管理器和适配器: ```java // 找到RecyclerView RecyclerView recyclerView = findViewById(R.id.recyclerview); // 设置布局管理器 recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 设置适配器 recyclerView.setAdapter(adapter); ``` 3. 创建一个自定义的ItemDecoration类(例如:FloatingHeaderDecoration.java): ```java public class FloatingHeaderDecoration extends RecyclerView.ItemDecoration { private View mFloatingView; public FloatingHeaderDecoration(View floatingView) { mFloatingView = floatingView; } @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (parent.getChildAdapterPosition(view) == 0) { outRect.top = mFloatingView.getHeight(); } } @Override public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.onDraw(canvas, parent, state); int top = parent.getPaddingTop(); int bottom = top + mFloatingView.getHeight(); int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); mFloatingView.setVisibility(View.VISIBLE); mFloatingView.layout(left, top, right, bottom); mFloatingView.draw(canvas); } } ``` 4. 在Activity或Fragment中,为RecyclerView添加ItemDecoration: ```java // 找到悬浮视图 View floatingView = findViewById(R.id.floating_view); // 创建自定义的ItemDecoration并添加到RecyclerView recyclerView.addItemDecoration(new FloatingHeaderDecoration(floatingView)); ``` 这样就实现RecyclerView悬浮吸顶效果。悬浮视图会在滚动时始终保持在顶部,并且不会被其他项覆盖。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值