Android RecyclerView 梦幻般的控件 使用解析(三)

前言

首先和大家道个歉,实在是不好意思,距离上次博客过了很久才更新,由于新项目启动,朋友那边又要我帮他做个辅助,加上元旦放假,的确耽误了很久,现在基本项目工作进度稳定下来,我也要恢复进度,保持博客的稳定了。也不知道大家最近啥时候回家过年,时间也快到年底了,大家是不是都在等年终奖呢,然后回家发红包,哈哈。不过我最近还遇到点生活上麻烦的事情,嗨,感觉又要奔波,又要折腾一次了。

源码下载地址在最后!~

简介

先来看一下上次我们讲了什么,如果没有看过前面两篇博文的,可以先去阅读以下Android RecyclerView 梦幻般的控件 使用解析(一)Android RecyclerView 梦幻般的控件 使用解析(二)。之前我们讲的东西也比较简单,就是基本如何使用RecyclerView和怎么添加分隔线,今天开始才是RecyclerView的魅力所在,让我们看看梦幻般的她吧~!

使用方法

先把上次留下来的问题再补充一下哈,我们要怎么自定义分隔线呢?大家也都知道了,我们自定义一个itemdecoration_bg.xml,然后这个东西就比较随性了,大家可以发挥各自的艺术细胞,当然我只有艺术细菌,也简单给大家写一个看看吧,如下:

<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <gradient  android:centerColor="#0000ff" android:endColor="#00ff00" android:startColor="#00ffff" android:type="linear" />
    <size android:height="2dp" android:width="2dp"/>
    <padding  android:left="5dp" android:top="1dp" android:right="5dp"/>
</shape>

《Android RecyclerView 梦幻般的控件 使用解析(三)》

基本上我的艺术细菌也就这么多了,大家可以根据具体需求去画,反正这个东西比较自由随意。OK那么我们继续,看来这么多,再加上前面的两篇博文,的确这个东西用起来好像也真的不简单,至少比以前的ListView要麻烦,好了,关键点来了,我们来看下一,我如果这个改一下呢?看代码

recyhclerView = (RecyclerView) findViewById(R.id.recycleView);
//recyhclerView.setLayoutManager(new LinearLayoutManager(this));
recyhclerView.setLayoutManager(new GridLayoutManager(this,4));
recyhclerView.setAdapter(new MyRecyclerAdapter());

《Android RecyclerView 梦幻般的控件 使用解析(三)》

是不是很神奇,对的,一下子将ListView效果变成了GridView,你想,比如你是商城类的一个APP,在ListView和GridView之间切换是不是超级容易,有木有啊。好了,接下来我们就来讲一下这个LayoutManager吧。

RecyclerView.LayoutManager看源码

public static abstract class LayoutManager {
        ChildHelper mChildHelper;
        RecyclerView mRecyclerView;

这是一个抽象类,好在系统提供了3个实现类:

LinearLayoutManager 现行管理器,支持横向、纵向。
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器

那么我们再来看一下后面那个瀑布式布局,改一下代码:

recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));

当然这样的写法实现效果和GridView是一样的,但是注意一下,StaggeredGridLayoutManager的第二个参数是Orientation,仔细看一下,我们刚才用的是VERTICAL,大家看意思就能明白了,接下来我们来试试
StaggeredGridLayoutManager.HORIZONTAL

recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL));

《Android RecyclerView 梦幻般的控件 使用解析(三)》

是不是很神奇,如果你需要一个横向的GridView,那么恭喜你,这个轻而易举就是可以实现。

当然,大家也发现了,我这个分隔线并不适用后面两种布局管理器,这里借鉴一下大神们的分隔线,如下:
DividerGridItemDecoration

package com.mic.blin.myrecyclerview;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

/** * Created by zhaocheng on 2016/1/14. */
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
    private Drawable mDivider;

    public DividerGridItemDecoration(Context context)
    {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, State state)
    {

        drawHorizontal(c, parent);
        drawVertical(c, parent);

    }

    private int getSpanCount(RecyclerView parent)
    {
        // 列数
        int spanCount = -1;
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager)
        {

            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager)
        {
            spanCount = ((StaggeredGridLayoutManager) layoutManager)
                    .getSpanCount();
        }
        return spanCount;
    }

    public void drawHorizontal(Canvas c, RecyclerView parent)
    {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++)
        {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent)
    {
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++)
        {
            final View child = parent.getChildAt(i);

            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
                                int childCount)
    {
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager)
        {
            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager)
        {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL)
            {
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                {
                    return true;
                }
            } else
            {
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }

    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
                              int childCount)
    {
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager)
        {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
                return true;
        } else if (layoutManager instanceof StaggeredGridLayoutManager)
        {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            // StaggeredGridLayoutManager 且纵向滚动
            if (orientation == StaggeredGridLayoutManager.VERTICAL)
            {
                childCount = childCount - childCount % spanCount;
                // 如果是最后一行,则不需要绘制底部
                if (pos >= childCount)
                    return true;
            } else
            // StaggeredGridLayoutManager 且横向滚动
            {
                // 如果是最后一行,则不需要绘制底部
                if ((pos + 1) % spanCount == 0)
                {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void getItemOffsets(Rect outRect, int itemPosition,
                               RecyclerView parent)
    {
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
        {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                    mDivider.getIntrinsicHeight());
        }
    }
}

其实东西并不复杂,主要在getItemOffsets方法中,去判断是不是最后一行,如果是最后一行,则不需要绘制底部的分隔线了,如果是最后一列的话,那就不需要绘制右边的分隔线了,去理解一下就可以了,主要学习人家的思想,如何自己去绘制不重要。效果图:
《Android RecyclerView 梦幻般的控件 使用解析(三)》

我们继续看瀑布流布局,其实我们已经实现了,因为我们的高度是固定写死的,如果我们把高度设置成随机呢,我们来试试,我们在我们的适配器onBindViewHolder方法中来随机设置item的高度。

@Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
            lp.height = (int) (100 + Math.random() * 300);
            holder.tv.setLayoutParams(lp);
            holder.tv.setText(data.get(position));
        }

有木有很容易啊,一下子就实现了瀑布流,毕竟写个瀑布流还是挺麻烦的。
《Android RecyclerView 梦幻般的控件 使用解析(三)》

总结

总的来说,RecyclerView这个控件还是非常好用的,也是非常人性化的,当然也是对以前的ListView和GridView等控件的一种整合吧,把更多的自由交给开发人员,简单用法很简单,当然如果要加入点击事件,滑动事件,触摸时间,下拉,上拉事件的话,答题思路和ListView肯定是差不多的,所以大家有兴趣也可以去自己尝试写一下,东西不难,但是好用。

PS

到这里,大家不知道还怎么看待这个控件,我是超级喜欢的,我觉得也不用多久,基于RecyclerView的第三方类似于RefreshListView的框架也会横空出世吧。基本上RecyclerView也就讲到这里了,毕竟生活在上海,现在各种繁琐的事情,今晚回家又有烦心事要处理,真的是像狗一样的生活。

下载地址

http://download.csdn.net/detail/qq_25867141/9404331

    原文作者:BlinCheng
    原文地址: https://blog.csdn.net/qq_25867141/article/details/50516326
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞