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>

未完待续……

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

时间: 2024-10-26 16:27:04

Android RecyclerView网格布局(支持多种分割线)详解(2)的相关文章

Android RecyclerView添加头部和底部实例详解

Android RecyclerView添加头部和底部实例详解 如果只是想添加头部,可是使用GitHub里面这个项目,它可以为LinearLayoutManager,GridLayoutManager ,StaggeredGridLayoutManager布局的RecyclerView添加header.使用起来也十分简单: 只需将RecyclerViewHeader布局放在RecyclerView的上层. <FrameLayout android:layout_width="match_p

Android 拦截返回键事件的实例详解

Android 拦截返回键事件的实例详解 KeyEvent类 Android.View.KeyEvent类中定义了一系列的常量和方法,用来描述Android中的 按键事件和返回键有关的常量和方法有. KeyEvent.KEYCODE_BACK: 表示key类型为返回键 KeyEvent.ACTION_DOWN:表示事件为按下key,如果一直按住不放,则会不停产生此事件. KeyEvent.ACTION_UP:表示事件为为放开key,一次点击key过程只会调用一次. public final in

Android xmlns 的作用及其自定义实例详解

Android xmlns 的作用及其自定义实例详解 xmlns:Android="http://schemas.android.com/apk/res/android的作用是: 这个是xml的命名空间,有了他,你就可以alt+/作为提示,提示你输入什么,不该输入什么,什么是对的,什么是错的,也可以理解为语法文件.或者语法判断器什么的 这个主要作用是在运行的时候那些控件的属性都是通过它来识别的,如果上面你写错了,不会有任何问题,但是在运行的时候就会有问题,提示你没有指定宽度等什么.这个是不用联网

Android编程实现自定义手势的方法详解_Android

本文实例讲述了Android编程实现自定义手势的方法.分享给大家供大家参考,具体如下: 之前介绍过如何在Android程序中使用手势,主要是系统默认提供的几个手势,这次介绍一下如何自定义手势,以及如何对其进行管理. 先介绍一下Android系统对手势的管理,Android系统允许应用程序把用户的手势以文件的形式保存以前,以后要使用这些手势只需要加载这个手势库文件即可,同时Android系统还提供了诸如手势识别.查找及删除等的函数接口,具体如下: 一.加载手势库文件: staticGestureL

我的Android进阶之旅------&amp;gt;HTTP Header 详解

HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议.HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应.就整个网络资源传输而言,包括message-header和message-body两部分.首先传递message- header,即http header消息.http header 消息通常被分为4个部分:general  header, request header, response header, enti

Android学习笔记之ContentProvider和Uri详解_Android

本文介绍了自定义Content Provider的相关内容,完全解析内容提供者的用法.Content Provider,内容提供者,相信大家对这个组件的名字都不陌生,可能是自己平时做的都是一些简单的App,所以对于Content Provider的使用并不是很多,也不是特别熟悉.但是这里还是对Content Provider作个简单的总结,不是很深入,但是希望能给包括我在内的初学者一点帮助,看完这篇能对这个组件有个总体上的了解. 一.使用ContentProvider(内容提供者)共享数据 Co

Android中asset和raw的区别详解_Android

*res/raw和assets的相同点: 1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制. *res/raw和assets的不同点: 1.res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename:assets文件夹下的文件不会被映射到 R.java中,访问的时候需要AssetManager类. 2.res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹 *读取文件资源

Android控件之ListView用法实例详解_Android

本文实例讲述了Android控件之ListView用法.分享给大家供大家参考.具体如下: 示例一: 在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示. main.xml布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/LinearLayout01" androi

Android Activity的跳转与传值详解

Android Activity的跳转与传值详解 Activity跳转与传值,主要是通过Intent类来连接多个Activity,以及传递数据. Intent是Android一个很重要的类.Intent直译是"意图",什么是意图呢?比如你想从这个Activity跳转到另外一个Activity,这就是一个意图.Intent类在Android系统中的作用很大,在此不详细说了,后面有文章介绍! Activity跳转,无返回结果 这是最简单的Activity跳转方式.从一个Activity启动