美文网首页
用RecyclerView的ItemDecoration实现粘性

用RecyclerView的ItemDecoration实现粘性

作者: 秦将王翦破赵 | 来源:发表于2018-08-16 17:26 被阅读0次

    通过ItemDecoration来实现类似联系人列表的粘性头部效果,如下图:

    效果图

    定义实体类

    public class GroupItem {
        private String content;//item的内容字符串
        private boolean isFirst;//是否是该组第一项
        private String groupId;//所属组的id
    
        public GroupItem(String content, boolean isFirst, String groupId) {
            this.content = content;
            this.isFirst = isFirst;
            this.groupId = groupId;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public boolean isFirst() {
            return isFirst;
        }
    
        public void setFirst(boolean first) {
            isFirst = first;
        }
    
        public String getGroupId() {
            return groupId;
        }
    
        public void setGroupId(String groupId) {
            this.groupId = groupId;
        }
    }
    

    Deconation的代码如下:

    public class HfyDecoration extends RecyclerView.ItemDecoration {
        private Paint paint;
        private GroupInterface groupInterface;
    
        public HfyDecoration(GroupInterface groupInterface) {
            paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(true);
            this.groupInterface = groupInterface;
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int index = parent.getChildAdapterPosition(view);
            if (groupInterface.isFirst(index)) {
                //如果是分组第一个,绘制高度为100px的标题
                outRect.set(0, 100, 0, 0);
            } else {
                //普通item,和分组首个的顶部撑开的空间不一样,只绘制5px的分割线
                outRect.set(0, 5, 0, 0);
            }
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View view = parent.getChildAt(i);
                int index = parent.getChildAdapterPosition(view);
                if (groupInterface.isFirst(index)) {
                    //如果是分组第一个,绘制标题
                    float left = view.getLeft();
                    float top = view.getTop() - 100;
                    float bottom = view.getTop();
                    float right = view.getRight();
                    paint.setColor(Color.BLUE);
                    c.drawRect(left, top, right, bottom, paint);
                    paint.setColor(Color.RED);
                    paint.setTextSize(100);
                    c.drawText(groupInterface.getGroupId(index), left, bottom, paint);
                } else {
                    //不是本组第一个,就绘制普通分割线
                    float left = view.getLeft();
                    float top = view.getTop() - 5;
                    float bottom = view.getTop();
                    float right = view.getRight();
                    //绘制矩形作为分割线
                    c.drawRect(left, top, right, bottom, paint);
                }
    
            }
        }
    
        @Override
        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDrawOver(c, parent, state);
            //绘制顶部标题的坐标
            float left = parent.getLeft();
            float top = parent.getTop();
            float bottom = parent.getTop() + 100;
            float right = parent.getRight();
    
            int count = parent.getChildCount();
    
            //当前可见的第一个item
            View firstVisibleView = parent.getChildAt(0);
            //当前可见的第一个item在数据源中的index
            int firstVisbleIndex = parent.getChildAdapterPosition(firstVisibleView);
            //当前可见的第一个item的分组id
            String firstVisibleGroupId = groupInterface.getGroupId(firstVisbleIndex);
            //当前可见的第二个分组的第一个item在RecyclerView的可见位置,默认-1表示可见项没有第二个组
            int secondGroupFirstPosition = -1;
            //遍历当前可见的第一个之后的所有item(随着滑动,会不断调用,不断遍历实时的新的可见item)
            for (int i = 1; i < count; i++) {
                View item = parent.getChildAt(i);
                int index = parent.getChildAdapterPosition(item);
                if (!firstVisibleGroupId.equals(groupInterface.getGroupId(index))) {
                    //如果和第一个可见item不是同一组,即当前可见的第二组的第一个item
                    secondGroupFirstPosition = i;
                    //找到了可见的第二组的第一个item,就停止循环
                    break;
                }
            }
            //核心思想就是找到可见的第二个组的第一个view,如果这个view距顶部滑动到了两个标题的高度以内,
            // 即两个组的标题发生接触,就根据这个view的位置,修改绘制第一组的标题位置
    
            //如果secondGroupFirstPosition是-1,会返回null
            View secondGroupFirstView = parent.getChildAt(secondGroupFirstPosition);
            if (secondGroupFirstView != null && secondGroupFirstView.getTop() <= 200) {
                //第二组的第一个滑动到了特定距离,距顶部两个标题的高度,就开始跟随移动
                paint.setColor(Color.BLUE);
                //根据第二组的第一个view的top来设置第一组的标题位置,就产生了跟随滑动被顶上去的效果
                c.drawRect(left, secondGroupFirstView.getTop() - 200, right, secondGroupFirstView.getTop() - 100, paint);
                paint.setColor(Color.RED);
                //绘制文字同理
                c.drawText(groupInterface.getGroupId(firstVisbleIndex), left, secondGroupFirstView.getTop() - 100, paint);
            } else {
                //第二组的第一项没有滑到特定距离,或者可见只有一个组,就固定顶部显示第一组的标题id
                paint.setColor(Color.BLUE);
                c.drawRect(left, top, right, bottom, paint);
                paint.setColor(Color.RED);
                c.drawText(groupInterface.getGroupId(firstVisbleIndex), left, bottom, paint);
            }
        }
    
        public interface GroupInterface {
    
            boolean isFirst(int index);
    
            String getGroupId(int index);
        }
    }
    

    activity的代码如下:

    public class MainActivity extends AppCompatActivity {
    
        private RecyclerView recyclerView;
    
        @Override
        protected void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            recyclerView = findViewById(R.id.recycler_view);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
    
            final ArrayList<GroupItem> list = new ArrayList<>();
            initData(list);
            //实现接口
            recyclerView.addItemDecoration(new HfyDecoration(new HfyDecoration.GroupInterface() {
                @Override
                public boolean isFirst(int index) {
                    return list.get(index).isFirst();
                }
    
                @Override
                public String getGroupId(int index) {
                    return list.get(index).getGroupId();
                }
            }));
            recyclerView.setAdapter(new HfyAdapter(list));
        }
    
        private void initData(ArrayList<GroupItem> list) {
            list.add(new GroupItem("aa", true, "a"));
            list.add(new GroupItem("aaa", false, "a"));
            list.add(new GroupItem("aaaa", false, "a"));
            list.add(new GroupItem("aaa", false, "a"));
    
            list.add(new GroupItem("bb", true, "b"));
            list.add(new GroupItem("bbb", false, "b"));
            list.add(new GroupItem("bbbb", false, "b"));
            list.add(new GroupItem("bbb", false, "b"));
    
            list.add(new GroupItem("cc", true, "c"));
            list.add(new GroupItem("ccc", false, "c"));
            list.add(new GroupItem("cccc", false, "c"));
            list.add(new GroupItem("ccc", false, "c"));
    
            list.add(new GroupItem("dd", true, "d"));
            list.add(new GroupItem("ddd", false, "d"));
            list.add(new GroupItem("dddd", false, "d"));
            list.add(new GroupItem("ddd", false, "d"));
    
            list.add(new GroupItem("ee", true, "e"));
            list.add(new GroupItem("eee", false, "e"));
            list.add(new GroupItem("eeee", false, "e"));
            list.add(new GroupItem("eee", false, "e"));
    
            list.add(new GroupItem("ff", true, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("ffff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
            list.add(new GroupItem("fff", false, "f"));
        }
    }
    

    相关文章

      网友评论

          本文标题:用RecyclerView的ItemDecoration实现粘性

          本文链接:https://www.haomeiwen.com/subject/rihobftx.html