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>

未完待续……

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

声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。