AndroidAndroid效果/自定义基础

Android ItemDecoration打造分组悬浮

2017-06-30  本文已影响221人  1da4ea6f4995

参考博客:http://www.jianshu.com/p/359b7524fa88

首先看一下实现效果
QQ20170630-122625.gif

关于 ItemDecoration 是什么能做什么不在这篇文章的包含范围以内,各位可以自行百度和google,这边主要是讲述使用 ItemDecoration 实现分组悬浮的效果。

前面简单的实现数据展示这里就不做叙述了,都是简单的操作,我们直接切入 ItemDecoration 自定义与使用。


一、首先自定义一个 ItemDecoration

新建一个类,继承 RecyclerView.ItemDecoration 类,并实现四个方法,分别是构造方法、onDraw()、onDrawOver()、getItemOsets()。

二、对数据进行分组

我们不能一口吃掉一个胖子,一步一步来分组悬浮第一步对信息进行分组。我们的目标是在分组之间添加分割线完成分组。
所以这一步操作我们要在 getOffsets() 中执行,主要代码如下,注释比较详细科技直接看代码,我的模拟数据为一组List<String>,循环加入30个数据,每组5条数据共六组,大家看上面演示就知道。

    /* 分组头部高度
![
![](http:https://img.haomeiwen.com/i2904262/a1abb1ce9b90b260.gif?imageMogr2/auto-orient/strip)
](http:https://img.haomeiwen.com/i2904262/e7adbc8f81ef4642.gif?imageMogr2/auto-orient/strip)
 */
    private int offsesSize = 30;
    private List<String> strings;
    /* 构造方法传入数据 */
    public DemoItemDecoration(List<String> strings) {
        super();
        this.strings = strings;
    }
@Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        /* 当前 item 的位置 */
        int position = parent.getChildAdapterPosition(view);
        /* 判断当前 item 是否和上一个 item 属于同一组,不同就需要设置分割线 */
        if (beforAndLater(position)) {
            outRect.set(0, offsesSize, 0, 0);
        }
    }

 /**
     * e
     * 当前 item 的数据和上一个数据进行比对,分组信息是否有差异。
     * @param postition
     * @return
     */
    private boolean beforAndLater(int postition) {
        /* positon 要大于零,要小于数据数量 */
        if (postition > 0) {
            /* 获取当前 item 的数据 */
            String beforStr = strings.get(postition);
            /* 获取上一个 item 的数据 */
            String laterStr = strings.get(postition - 1);
            /* 进行比对 */
            if (beforStr.substring(0).equals(laterStr.substring(0))) {
                return false;
            } else {
                return true;
            }
        }
         /* 第一条数据必定设置分组头部间隙 */
        if (postition == 0) {
            return true;
        }
        return false;
    }

效果如下:

QQ20170630-161426.gif
三、为头部绘制文字

分组成功了,但是每组头部并没有显示组名,现在我们来为分组头部添加组名。这个操作我们要在 onDraw() 方法进行操作。首先我们需要在构造方法中初始化两个 Paint(画笔) 一个背景,一个文字,这样我们在 onDraw() 中使用 canvas 进行绘制。

@Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        /* 获取子view个数 */
        int itemSum = parent.getChildCount();

        /* 获取 item 左右的 margin */
        int itemLeft = parent.getPaddingLeft();
        int itemRifht = parent.getWidth() - parent.getPaddingRight();

        /* 遍历 item 给需要绘制分组信息的绘制头部*/
        int j = 0;
        for (int i = 0; i < itemSum; i++) {
            /* 获取子 View */
            View childView = parent.getChildAt(i);
            /* 获取子 view的位置 */
            int position = parent.getChildAdapterPosition(childView);
            /*  获取子 view 的布局参数,方便确定头部位置 */
            RecyclerView.LayoutParams childParams = (RecyclerView.LayoutParams) childView.getLayoutParams();

            int itemTop = childView.getTop() - childParams.topMargin - offsesSize;
            int itemButtom = childView.getTop() - childParams.topMargin;

            /* 判定当前子 view 是否需要绘制头部,注意位置 */
            if (beforAndLater(position)) {
                /* 绘制头部背景 */
                c.drawRect(itemLeft, itemTop, itemRifht, itemButtom, testPaint);
                /* 绘制文字 */
                c.drawText(strings.get(position), itemLeft, itemButtom, textPaint);
            }
        }
    }

效果如下:

QQ20170630-163019.gif
四、绘制悬浮头部

高地已破,现在只要拔掉两个狼牙,干掉水晶我们就 Victory 了!
记住!记住!ItemDecoration 里面三个方法的调用步骤!这个很重要。我就在这个地方猜坑了,耽误的很多时间。
好了,我的思路是这样的。获取第一个可见的 itemview ,然后判断后面的一个 itemview 是否和第一个可见的 itemview 属于同一分组,如果不同我们就获取后面一个 itemview 底部距离 RecyclerView 顶部的距离(即 view.getBottom),然后与悬浮头部的固定 bottom 距离做比较,去相对较小的一个,然后进行绘制,代码如下:

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        /* 获取第一个可见view itemview */
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) parent.getLayoutManager();
        int firstChildViewPosition = linearLayoutManager.findFirstVisibleItemPosition();
        /* 这里出现了一个bug,用parent.getCildAt(),出现childView为空的现象,所以用这个方法 */
        View firseChildView = parent.findViewHolderForLayoutPosition(firstChildViewPosition).itemView;
        int left = parent.getLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        int top = parent.getPaddingTop();
        int bottom = parent.getPaddingTop() + offsesSize;

        /**
         * 上拉时,判定位于第一个可见 item 与下一个 item 是不是属于同一分组的,如果是悬浮条的位置( bottom )依然取 parent.getPaddingTop() + offsesSize
         *        当不是时,在获取可一个可见 itemview 的 Bottom(getBottom() 它的数值就是 itemview 距离 parent 顶部的距离)与 bottom 大小进行比较,哪个小就选哪个进行绘制悬浮条。
         * 下拉亦是如此。
         *
         */
        if (nowContrastNext(firstChildViewPosition)) {
            bottom = Math.min(firseChildView.getBottom(), bottom);
        }
        c.drawRect(0, top, right, bottom, testPaint);
        c.drawText(strings.get(firstChildViewPosition).substring(0), left, bottom, textPaint);
    }

然后运行就能得到头部悬停的效果了!

上一篇下一篇

猜你喜欢

热点阅读