Android RecyclerView网格布局(支持多种分割线)详解(2)

上篇Android RecyclerView 详解(1)—线性布局

记录了下RecyclerView的使用方法,并且讲述了线性布局列表的使用方法,在此基础上加上了万能分割线,支持颜色分割线和图片分割线,同时支持对分割线设置线宽。
这篇是总结一下网格布局的使用,同样也支持两种分割线和线宽的设置。

主要的相关类:

1. RecyclerView.Adapter

2. GridLayoutManager 网格布局管理器

3. RecycleView.ItemDecoration 分割线

下面就直接通过一个例子来展示:

先上效果图:

(1) 颜色分割线

看起来还不错吧,根据item的数量去显示格子,当然如果你需要的样式不是三列,这个很简单,只需要在设置
GridLayoutManager的时候设置相应的列数即可,即:

mManagerLayout = new GridLayoutManager(getActivity(), 3);

(2) 图片分割线

可能有人会说你的列表四周都有分割线,其实在不做特殊处理时左边和上面默认是没有分割线的。后面我会加上四周没有分割线的,其实这两种形式在实际开发中都是常见的,先来看四周都有边线的。

由于RecycleView是高度解耦的控件,绘制分割线只和 RecycleView.ItemDecoration 有关,所以我们只需关心怎么去继承 RecycleView.ItemDecoration 去实现我们所需的分割线,如下:

这里需要说明的是:颜色分割线和图片分割线原理是完全一样的,图片分割线只是将一张很细的图片传入即可。

public class GridDivider extends RecyclerView.ItemDecoration {
  private Drawable mDividerDarwable;
  private int mDividerHight = 1;
  private Paint mColorPaint;
  public final int[] ATRRS = new int[]{android.R.attr.listDivider};

  public GridDivider(Context context) {
    final TypedArray ta = context.obtainStyledAttributes(ATRRS);
    this.mDividerDarwable = ta.getDrawable(0);
    ta.recycle();
  }

  /*
   int dividerHight 分割线的线宽
   int dividerColor 分割线的颜色
   */
  public GridDivider(Context context, int dividerHight, int dividerColor) {
    this(context);
    mDividerHight = dividerHight;
    //绘制颜色分割线的画笔
    mColorPaint = new Paint();
    mColorPaint.setColor(dividerColor);
  }

  /*
   int dividerHight 分割线的线宽
   Drawable dividerDrawable 图片分割线
   */
  public GridDivider(Context context, int dividerHight, Drawable dividerDrawable) {
    this(context);
    mDividerHight = dividerHight;
    mDividerDarwable = dividerDrawable;
  }

  @Override
  public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    super.onDraw(c, parent, state);
    //画水平和垂直分割线
    drawHorizontalDivider(c, parent);
    drawVerticalDivider(c, parent);
  }

  public void drawVerticalDivider(Canvas c, RecyclerView parent) {
    // 这里传入的parent是recycleview,通过它我们可以获取列表的所有的元素,
    // 这里我们遍历列表中的每一个元素,对每一个元素绘制垂直分割线
    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
      final View child = parent.getChildAt(i);
      //获取当前item布局参数,通过它可以知道该item的精确位置,我们通过这个位置去绘制它的分割线
      final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

      final int top = child.getTop() - params.topMargin;
      final int bottom = child.getBottom() + params.bottomMargin;

      int left = 0;
      int right = 0;

      //左边第一列,
      if ((i % 3) == 0) {
        //item左边分割线
        left = child.getLeft();
        right = left + mDividerHight;
        mDividerDarwable.setBounds(left, top, right, bottom);
        mDividerDarwable.draw(c);
        if (mColorPaint != null) {//如果是颜色分割线
          c.drawRect(left, top, right, bottom, mColorPaint);
        }
        //item右边分割线
        left = child.getRight() + params.rightMargin - mDividerHight;
        right = left + mDividerHight;
      } else {
        //非左边第一列
        left = child.getRight() + params.rightMargin - mDividerHight;
        right = left + mDividerHight;
      }
      //画分割线
      mDividerDarwable.setBounds(left, top, right, bottom);
      mDividerDarwable.draw(c);
      if (mColorPaint != null) {
        c.drawRect(left, top, right, bottom, mColorPaint);
      }
    }
  }
  //....水平分割线与垂直分割线类似,完整代码见下。
}

下面是完整代码:

1. MainActivity

public class MainActivity extends AppCompatActivity {

  private GridFragment mGridFragment;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //网格
    mGridFragment = new GridFragment();
    getFragmentManager().beginTransaction().replace(R.id.activity_main, mGridFragment).commit();
  }

activity_main

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
</FrameLayout>

2. GridFragment

public class GridFragment extends Fragment implements View.OnClickListener{

  private RecyclerView mRecycleViewDrawable;
  private RecyclerView mRecycleViewColor;
  private LinearLayoutManager mManagerColor;
  private LinearLayoutManager mManagerDrawable;
  private List<String> mData;
  private Button mDrawable;
  private Button mColor;
  private MyRecycleViewAdapter mRecycleViewAdapter;

  @Nullable
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_grid_layout, container, false);
    mRecycleViewDrawable = (RecyclerView) view.findViewById(R.id.recycleview_drawable);
    mRecycleViewColor = (RecyclerView) view.findViewById(R.id.recycleview_color);

    mDrawable = (Button) view.findViewById(R.id.btn_drawable);
    mDrawable.setOnClickListener(this);
    mColor = (Button) view.findViewById(R.id.btn_color);
    mColor.setOnClickListener(this);

    //设置颜色分割线
    mManagerColor = new GridLayoutManager(getActivity(), 3);
    mRecycleViewColor.setLayoutManager(mManagerColor);
    mRecycleViewColor.addItemDecoration(new GridDivider(getActivity(), 20, this.getResources().getColor(R.color.colorAccent)));

    //设置图片分割线
    mManagerDrawable = new GridLayoutManager(getActivity(), 3);
    mRecycleViewDrawable.setLayoutManager(mManagerDrawable);
    Drawable drawable = ContextCompat.getDrawable(getActivity(), R.mipmap.divider);
    mRecycleViewDrawable.addItemDecoration(new GridDivider(getActivity(), 20, drawable));

    //初始化数据
    mData = new ArrayList<String>();
    initData(mData);
    mRecycleViewAdapter = new MyRecycleViewAdapter(getActivity(), R.layout.item_grid_recycleview, mData);

    mRecycleViewColor.setAdapter(mRecycleViewAdapter);
    mRecycleViewDrawable.setAdapter(mRecycleViewAdapter);

    return view;
  }

  private void initData(List<String> dataList) {
    for (int i = 0; i < 16; i++) {
      dataList.add("item" + i);
    }
  }

  @Override
  public void onClick(View view) {
    int id = view.getId();
    switch (id){
      case R.id.btn_drawable:
        mRecycleViewColor.setVisibility(View.INVISIBLE);
        mRecycleViewDrawable.setVisibility(View.VISIBLE);
        break;

      case R.id.btn_color:
        mRecycleViewColor.setVisibility(View.VISIBLE);
        mRecycleViewDrawable.setVisibility(View.INVISIBLE);
        break;
    }
  }
}

3.分割线 GridDivider

直接继承 RecyclerView.ItemDecoration

public class GridDivider extends RecyclerView.ItemDecoration {

  private Drawable mDividerDarwable;
  private int mDividerHight = 1;
  private Paint mColorPaint;

  public final int[] ATRRS = new int[]{android.R.attr.listDivider};

  public GridDivider(Context context) {
    final TypedArray ta = context.obtainStyledAttributes(ATRRS);
    this.mDividerDarwable = ta.getDrawable(0);
    ta.recycle();
  }

  /*
   int dividerHight 分割线的线宽
   int dividerColor 分割线的颜色
   */
  public GridDivider(Context context, int dividerHight, int dividerColor) {
    this(context);
    mDividerHight = dividerHight;
    mColorPaint = new Paint();
    mColorPaint.setColor(dividerColor);
  }

  /*
   int dividerHight 分割线的线宽
   Drawable dividerDrawable 图片分割线
   */
  public GridDivider(Context context, int dividerHight, Drawable dividerDrawable) {
    this(context);
    mDividerHight = dividerHight;
    mDividerDarwable = dividerDrawable;
  }

  @Override
  public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    super.onDraw(c, parent, state);
    //画水平和垂直分割线
    drawHorizontalDivider(c, parent);
    drawVerticalDivider(c, parent);
  }

  public void drawVerticalDivider(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;

      int left = 0;
      int right = 0;

      //左边第一列
      if ((i % 3) == 0) {
        //item左边分割线
        left = child.getLeft();
        right = left + mDividerHight;
        mDividerDarwable.setBounds(left, top, right, bottom);
        mDividerDarwable.draw(c);
        if (mColorPaint != null) {
          c.drawRect(left, top, right, bottom, mColorPaint);
        }
        //item右边分割线
        left = child.getRight() + params.rightMargin - mDividerHight;
        right = left + mDividerHight;
      } else {
        //非左边第一列
        left = child.getRight() + params.rightMargin - mDividerHight;
        right = left + mDividerHight;
      }
      //画分割线
      mDividerDarwable.setBounds(left, top, right, bottom);
      mDividerDarwable.draw(c);
      if (mColorPaint != null) {
        c.drawRect(left, top, right, bottom, mColorPaint);
      }

    }
  }

  public void drawHorizontalDivider(Canvas c, RecyclerView parent) {

    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
      final View child = parent.getChildAt(i);
      RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

      final int left = child.getLeft() - params.leftMargin - mDividerHight;
      final int right = child.getRight() + params.rightMargin;
      int top = 0;
      int bottom = 0;

      // 最上面一行
      if ((i / 3) == 0) {
        //当前item最上面的分割线
        top = child.getTop();
        //当前item下面的分割线
        bottom = top + mDividerHight;
        mDividerDarwable.setBounds(left, top, right, bottom);
        mDividerDarwable.draw(c);
        if (mColorPaint != null) {
          c.drawRect(left, top, right, bottom, mColorPaint);
        }
        top = child.getBottom() + params.bottomMargin;
        bottom = top + mDividerHight;
      } else {
        top = child.getBottom() + params.bottomMargin;
        bottom = top + mDividerHight;
      }
      //画分割线
      mDividerDarwable.setBounds(left, top, right, bottom);
      mDividerDarwable.draw(c);
      if (mColorPaint != null) {
        c.drawRect(left, top, right, bottom, mColorPaint);
      }
    }
  }
}

4. Adapter

public class MyRecycleViewAdapter extends RecyclerView.Adapter<MyRecycleViewAdapter.MyViewHolder> {

  private LayoutInflater mLayoutInflater;
  private List<String> mDataList;
  private int mItemLayout;

  public MyRecycleViewAdapter(Context context, int itemLayout, List<String> datalist) {
    mLayoutInflater = LayoutInflater.from(context);
    mItemLayout = itemLayout;
    mDataList = datalist;
  }

  @Override
  public MyRecycleViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new MyViewHolder(mLayoutInflater.inflate(mItemLayout, parent, false));
  }

  @Override
  public void onBindViewHolder(MyRecycleViewAdapter.MyViewHolder holder, int position) {
    holder.mTextView.setText(mDataList.get(position));
  }

  @Override
  public int getItemCount() {
    return mDataList.size();
  }

  class MyViewHolder extends RecyclerView.ViewHolder {

    private TextView mTextView;

    public MyViewHolder(View itemView) {
      super(itemView);
      mTextView = (TextView) itemView.findViewById(R.id.tv);
    }
  }
}

adapter 的item布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content">

  <TextView
    android:id="@+id/tv"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="60dp"/>

</FrameLayout>

未完待续……

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android使用RecyclerView实现水平滚动控件

    前言 相信大家都知道Android滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点: (1) 对齐控件中心位置. (2) 计算滚动距离. (3) 高亮中心视图. (4) 实时显示中心数据. (5) 停止时自动对齐. (6) 滚动时, 设置按钮状态开关. 效果 1. 框架 主要关注RecyclerView部分逻辑. /** * 初始化年龄滑动条 */ private void ini

  • Android项目实战之仿网易新闻的页面(RecyclerView )

    本文实例实现一个仿网易新闻的页面,上面是轮播的图片,下面是 RecyclerView 显示新闻列表,具体内容如下 错误方法 <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...> <ViewPager ... /> <android.support.v7.widget.RecyclerView .../> </LinearLayout> 这样布局

  • Android中RecyclerView嵌套滑动冲突解决的代码片段

    在纵向RecyclerView嵌套横向RecyclerView时,如果纵向RecyclerView有下拉刷新功能,那么内部的横向RecyclerView的横向滑动体验会很差.(只有纯横向滑动时,才能滑动内部的横向RecyclerView,否则滑动事件就会影响到下拉刷新),添加拦截判断. public class MySwipeRefreshLayout extends SwipeRefreshLayout { private boolean mIsVpDragger; private final

  • Android中RecyclerView实现横向滑动代码

    RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍Android中RecyclerView实现横向滑动代码,一起看看吧. android.support.v7.widget.RecyclerView 功能:RecyclerView横向滑动 控件:<android.support.v7.widget.RecyclerView /> Java类:RecyclerView.GalleryAdap

  • Android中使用RecyclerView实现下拉刷新和上拉加载

    推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie

  • Android中RecyclerView布局代替GridView实现类似支付宝的界面

    单纯使用GridView 通用的两种给GridView 添加分割线的方法:http://stackoverflow.com/questions/7132030/android-gridview-draw-dividers 给Gridview 添加分割线,也就是实现网格布局,不清楚谷歌为什么没有给Gridview 添加一个类似 ListView 的Divider 属性,因此就需要我们自己去添加分割线, 目前两种方法,第一种是 利用GridView 的  android:horizontalSpac

  • Android控件RecyclerView实现混排效果仿网易云音乐

    前言 最近在使用网易云音乐的时候,看到如下图的排版效果图,自己也想实现一个 这里采用网上用法最多的方式,而且是比较简单的方式实现的,想要做项目的同学也可以快速入手搞定首页界面,可以在最快的时间内模仿出来,且效果达到90%以上的相似 效果演示 至于图片的加载你们可以根据网上的Api获取相应的图片加载到对应的位置,这里只是采用本地图片来演示 实现分析 这里是采用RecyclerView的GridLayoutManager的一个SpanSize这么一个东西,从下图很容易知道其意思 项目结构 项目结构可

  • Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法

    RecyclerView 已经出来很久了,但是在项目中之前都使用的是ListView,最近新的项目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,网上吧啦吧啦没有合适的自己总结了一哈. 先贴图上来看看: 使用RecyclerView实现上拉加载更多和下拉刷新的功能我自己有两种方式: 1.使用系统自带的Android.support.v4.widget.SwipeRefreshLayout这个控价来实现. 2.自定义的里面带有RecyleView的控件. 使用RecycleVie

  • Android RecyclerView实现下拉刷新和上拉加载

    RecyclerView已经出来很久了,许许多多的项目都开始从ListView转战RecyclerView,那么,上拉加载和下拉刷新是一件很有必要的事情. 在ListView上,我们可以通过自己添加addHeadView和addFootView去添加头布局和底部局实现自定义的上拉和下拉,或者使用一些第三方库来简单的集成,例如Android-pulltorefresh或者android-Ultra-Pull-to-Refresh,后者的自定义更强,但需要自己实现上拉加载. 而在下面我们将用两种方式

  • Android中RecyclerView点击Item设置事件

    在上一篇Android RecylerView入门教程中提到,RecyclerView不再负责Item视图的布局及显示,所以RecyclerView也没有为Item开放OnItemClick等点击事件,这就需要开发者自己实现.博客最下面有Demo程序运行动画. 奉上Demo的Github链接. 在调研过程中,发现有同学修改RecyclerView源码来实现Item的点击监听,但认为这不是一个优雅的解决方案,最终决定在RecyclerView.ViewHolder上做文章. 思路是:因为ViewH

随机推荐