00-Unit_Common综述-RecyclerView封装

时间:2021-07-07 22:11:38
自学安卓也有一年的时间了,与代码相伴的日子里,苦乐共存。能坚持到现在确实已见到了“往日所未曾见证的风采”。今2018年4月2日,决定用一个案例:Unit_Common,把安卓基础的知识进行串联,形成模块化的总结性测试案例,一方面是对自己的总结,在总结中温故知新。另一方面通过博客,和众多开发爱好者进行知识分享,希望可以帮助到一些新入安卓的人。
本项目通过一个RecyclerView进行模块的划分,点击item进入相应模块。所以本篇先用RecyclerView将整个案例的框架搭建出来,这篇对新手可能比较难以理解,但并不影响学习后面的简单知识。
 
为了方便查看将每个模块的名称和图片展示在RecyclerView的item上:
 1 package top.toly.www.unit_common.bean;
 2
 3 /**
 4  * 作者:张风捷特烈
 5  * 时间:2018/4/10:14:55
 6  * 邮箱:1981462002@qq.com
 7  * 说明:每个界面的bean对象 图片+名称
 8  */
 9 public class ItemBean {
10
11     private String name;
12     private int ResId;
13
14     public ItemBean(String name, int resId) {
15         this.name = name;
16         ResId = resId;
17     }
18
19     public String getName() {
20         return name;
21     }
22
23     public void setName(String name) {
24         this.name = name;
25     }
26
27     public int getResId() {
28         return ResId;
29     }
30
31     public void setResId(int resId) {
32         ResId = resId;
33     }
34 }
Activity_Home_RV 我们需要关注的是OnRvItemClick方法:通过位置打开模块。 setItemsData方法设置数据
 1 注:笔者为避免寻找id的麻烦,使用了ButterKnife
 2    依赖:implementation 'com.jakewharton:butterknife:7.0.1'
 3    混淆:#butterknife
 4   -keep class butterknife.** { *; }
 5   -dontwarn butterknife.internal.**
 6   -keep class **$$ViewBinder { *; }
 7   -keepclasseswithmembernames class * {
 8       @butterknife.* <fields>;
 9   }
10   -keepclasseswithmembernames class * {
11       @butterknife.* <methods>;
12   }
 1 package top.toly.www.unit_common.home;
 2
 3 import android.content.Intent;
 4 import android.os.Bundle;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.support.v7.widget.RecyclerView;
 7 import android.view.View;
 8
 9 import java.util.ArrayList;
10 import java.util.List;
11
12 import butterknife.Bind;
13 import butterknife.ButterKnife;
14 import top.toly.www.unit_common.R;
15 import top.toly.www.unit_common.activity.MainActivity;
16 import top.toly.www.unit_common.bean.ItemBean;
17 import utils.ev.recyclerview.MyRVAdapter;
18 import utils.ev.recyclerview.MyRVHolder;
19 import utils.ui.UIUtils;
20
21 public class Activity_Home_RV extends AppCompatActivity {
22
23     @Bind(R.id.recyclerview)
24     RecyclerView mRecyclerview;
25     private List<ItemBean> mItems;//itemBean的集合
26
27     @Override
28     protected void onCreate(Bundle savedInstanceState) {
29         super.onCreate(savedInstanceState);
30         setContentView(R.layout.activity_home_rv);
31         ButterKnife.bind(this);
32
33         setItemsData();//为item设置数据
34     initRV();//初始化RecyclerView
35
36     }
37
38     private void initRV() {
39         // 注:笔者已对RecyclerView进行封装,以下几行就搞定RecyclerView的简单使用,封装代码见下
40     UIUtils.setStyle4RV(mRecyclerview, 3, UIUtils.GRIDVIEW, this);//设置类型
41         MyRVAdapter<ItemBean> rvAdapter = new MyRVAdapter<ItemBean>(mItems, R.layout.rv_item_home) {
42             @Override
43             public void setDatas(MyRVHolder holder, ItemBean data, int position) {
44                 holder.setText(R.id.tv_title, data.getName())
45                         .setImageViewRes(R.id.iv_icon, data.getResId());
46             }
47         };
48
49         mRecyclerview.setAdapter(rvAdapter);
50         rvAdapter.setOnRvItemClickListener(new MyRVAdapter.OnRvItemClickListener() {
51             @Override
52             public void OnRvItemClick(View v, int pos) {
53                 switch (pos) {
54                     case 0:
55                         startActivity(new Intent(Activity_Home_RV.this, MainActivity.class));
56                         break;
57                 }
58             }
59         });
60     }
61
62     /**
63      * 为item设置数据
64      *
65      * @return
66      */
67
68     public List<ItemBean> setItemsData() {
69         mItems = new ArrayList<>();
70         mItems.add(new ItemBean("test", R.drawable.ic_launcher_background));
71 mItems.add(new ItemBean("test1", R.drawable.ic_launcher_background));
72         return mItems;
73     }
74
75 }
布局:

activity_home_rv.xml:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent">
 7
 8 <android.support.v7.widget.RecyclerView
 9     android:id="@+id/recyclerview"
10     android:layout_width="match_parent"
11     android:layout_height="wrap_content"/>
12
13 </RelativeLayout>
rv_item_home.xml:
 1 <?xml version="1.0" encoding="utf-8"?>
 2   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3                 android:layout_width="match_parent"
 4                 android:layout_height="wrap_content"
 5                 android:padding="5dp">
 6
 7         <ImageView
 8             android:id="@+id/iv_icon"
 9             android:layout_width="50dp"
10             android:layout_height="50dp"
11             android:src="@drawable/ic_launcher_background" />
12
13         <TextView
14             android:id="@+id/tv_title"
15             android:layout_width="match_parent"
16             android:layout_height="wrap_content"
17             android:layout_marginLeft="3dp"
18             android:layout_toRightOf="@+id/iv_icon"
19             android:layout_centerInParent="true"
20             android:text="Content"
21             android:textAllCaps="false"
22             android:textColor="#000000" />
23 </RelativeLayout>
效果如下:随着mItems数量增加,RecyclerView也会增加
 
 00-Unit_Common综述-RecyclerView封装
下面是笔者封装的代码:虽然比较多,但拷贝进去就能用。好了,综述就到这里。

对RecyclerView进行封装:两个类MyRVHolder和MyRVAdapter
 package utils.ev.recyclerview;

 import android.graphics.Bitmap;
 import android.support.v7.widget.RecyclerView;
 import android.util.SparseArray;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;

 import com.bumptech.glide.Glide;
 import com.bumptech.glide.load.engine.DiskCacheStrategy;

 import utils.ui.UIUtils;

 /**
  * 作者:张风捷特烈
  * 时间:2018/4/10:14:22
  * 邮箱:1981462002@qq.com
  * 说明:View的持有人
  */
 public class MyRVHolder extends RecyclerView.ViewHolder {

     //键值对中键是int类型使用SparseArray比map更好
     private SparseArray<View> mViews;//持有的所有View集合
     private View mItemView;//Item的

     public MyRVHolder(View itemView) {

         super(itemView);
         mItemView = itemView;
         mViews = new SparseArray<>();
     }

     /**
      * 获取pos
      *
      * @return
      */
     public int getPos() {
         return this.getLayoutPosition();
     }

     /**
      * 通过viewId获取控件
      *
      * @param viewId
      * @param <T>
      * @return
      */
     public <T extends View> T getView(int viewId) {
         View view = mViews.get(viewId);
         if (view == null) {
             view = mItemView.findViewById(viewId);
             mViews.put(viewId, view);//以id为键,view为值
         }
         return (T) view;
     }

     public View getItemView() {
         return mItemView;
     }

     /**
      * 设置item背景颜色
      */
     public MyRVHolder setColor(int color) {
         mItemView.setBackgroundColor(color);
         return this;
     }

     /**
      * 设置TextView文本方法
      *
      * @param viewId
      * @param text
      * @return
      */
     public MyRVHolder setText(int viewId, String text) {
         TextView view = getView(viewId);
         view.setText(text);
         return this;
     }

     /**
      * 通过资源id设置ImageView图片
      * @param viewId
      * @param resId
      * @return
      */
     public MyRVHolder setImageViewRes(int viewId, int resId) {
         ImageView view = getView(viewId);
         view.setImageResource(resId);
         return this;
     }

     /**
      * 通过Bitmap设置ImageView图片
      * @param viewId
      * @param bitmap
      * @return
      */
     public MyRVHolder setImageViewBitmap(int viewId, Bitmap bitmap) {
         ImageView view = getView(viewId);
         view.setImageBitmap(bitmap);
         return this;
     }

     /**
      * 通过url设置图片
      * @param viewId
      * @param url
      * @return
      */
     public MyRVHolder setImageViewUrl(int viewId, String url) {
         ImageView view = getView(viewId);
         //此处使用Glide进行Url类型图片的加载,如果未添加Glide依赖会报错
         //依赖: implementation 'com.github.bumptech.glide:glide:3.7.0'
         Glide.with(UIUtils.getContext())
                 .load(url)
                 .skipMemoryCache(false)
                 .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                 .into(view);

         return this;
     }

     /////////////////////可继续拓展完善,添加更多方法//////////////////////
 }
 package utils.ev.recyclerview;

 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 import android.view.ViewGroup;

 import java.util.List;

 import utils.ui.UIUtils;

 /**
  * 作者:张风捷特烈
  * 时间:2018/4/10:14:28
  * 邮箱:1981462002@qq.com
  * 说明:RecyclerView的Adapter封装类
  */
 public abstract class MyRVAdapter<T> extends RecyclerView.Adapter<MyRVHolder> {
     protected List<T> mDatas;
     protected int mItemId;
     private View mItemView;

     public MyRVAdapter(List<T> datas, int itemId) {
         mDatas = datas;
         mItemId = itemId;
     }

     @Override
     public MyRVHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         mItemView = UIUtils.inflate(mItemId);
         final MyRVHolder myRVHolder = new MyRVHolder(mItemView);
         //点击事件方式
         mItemView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {//使用回调实现点击监听
                 if (mOnRvItemClickListener != null) {
                     mOnRvItemClickListener.OnRvItemClick(v, myRVHolder.getPos());

                 }
             }
         });

         return myRVHolder;
     }

     @Override
     public void onBindViewHolder(MyRVHolder holder, int position) {

         setDatas(holder, mDatas.get(position), position);

     }

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

     /**
      * 抽象方法,通过holder可对各控件进行操作
      *
      * @param holder   View的持有人
      * @param data     数据
      * @param position 点击位置
      */
     public abstract void setDatas(MyRVHolder holder, T data, int position);

 ///////////////////////////////////////////////////////////

     /**
      * 添加item
      *
      * @param i
      * @param aNew
      */
     public void addData(int i, T aNew) {
         mDatas.add(i, aNew);
         notifyItemInserted(i);//刷新数据
     }

     /**
      * 删除item
      *
      * @param i
      */
     public void deleteData(int i) {
         mDatas.remove(i);
         notifyItemRemoved(i);//刷新数据
     }

     public View getItemView() {
         return mItemView;
     }

     /////////////////为RecyclerView设置点击监听接口/////////////////////////
     /**
      * 为RecyclerView设置点击监听接口
      */
     public interface OnRvItemClickListener {
         void OnRvItemClick(View v, int pos);//item被点击的时候回调方法
     }

     /**
      * 声明监听器接口对象
      */
     private OnRvItemClickListener mOnRvItemClickListener;

     /**
      * 设置RecyclerView某个的监听方法
      *
      * @param onRvItemClickListener
      */
     public void setOnRvItemClickListener(OnRvItemClickListener onRvItemClickListener) {
         mOnRvItemClickListener = onRvItemClickListener;
     }
 }

这样可以使用了,不过为了添加分割线,还有免去写一些初始化的设置方法,把其封装在我的UiUtils中,静态方法如下:
 
 ////////////////////////设置RecyclerView/////////////////////////////////////////
     public static final int GRIDVIEW = 0;
     public static final int LISTVIEW = 1;
     public static final int PULL = 2;

     /**
      *
      * @param rv  RecyclerView
      * @param count count 数量  LISTVIEW可随意
      * @param style 模式 GRIDVIEW  LISTVIEW  PULL
      * @param ctx  上下文
      */
     public static GridLayoutManager setStyle4RV(RecyclerView rv, int count, int style,Context ctx) {
         switch (style) {
             case GRIDVIEW://GridView类型
                 rv.addItemDecoration(new MyDividerItemDecoration(ctx));//设置分割线
                 GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), count, GridLayoutManager.VERTICAL, false);
                 rv.setLayoutManager(gridLayoutManager);
                 return gridLayoutManager;
             case LISTVIEW://ListView类型
                 rv.addItemDecoration(new SampleDivider(ctx));
                 rv.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
                 return null;
             case PULL://瀑布流类型
                 rv.addItemDecoration(new MyDividerItemDecoration(ctx));
                 rv.setLayoutManager(new StaggeredGridLayoutManager(count, StaggeredGridLayoutManager.VERTICAL));
                 return null;
         }
         return null;
     }
MyDividerItemDecoration 分割线:
 package utils.ev.recyclerview;

 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.OrientationHelper;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;

 public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {

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

     /**
      * 用于绘制间隔样式
      */
     private Drawable mDivider;

     public MyDividerItemDecoration(Context context) {
         // 获取默认主题的属性
         final TypedArray a = context.obtainStyledAttributes(ATTRS);
         mDivider = a.getDrawable(0);
         a.recycle();
     }

     @Override
     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
         // 绘制间隔,每一个item,绘制右边和下方间隔样式
         int childCount = parent.getChildCount();
         int spanCount = ((GridLayoutManager)parent.getLayoutManager()).getSpanCount();
         int orientation = ((GridLayoutManager)parent.getLayoutManager()).getOrientation();
         boolean isDrawHorizontalDivider = true;
         boolean isDrawVerticalDivider = true;
         int extra = childCount % spanCount;
         extra = extra == 0 ? spanCount : extra;
         for(int i = 0; i < childCount; i++) {
             isDrawVerticalDivider = true;
             isDrawHorizontalDivider = true;
             // 如果是竖直方向,最右边一列不绘制竖直方向的间隔
             if(orientation == OrientationHelper.VERTICAL && (i + 1) % spanCount == 0) {
                 isDrawVerticalDivider = false;
             }

             // 如果是竖直方向,最后一行不绘制水平方向间隔
             if(orientation == OrientationHelper.VERTICAL && i >= childCount - extra) {
                 isDrawHorizontalDivider = false;
             }

             // 如果是水平方向,最下面一行不绘制水平方向的间隔
             if(orientation == OrientationHelper.HORIZONTAL && (i + 1) % spanCount == 0) {
                 isDrawHorizontalDivider = false;
             }

             // 如果是水平方向,最后一列不绘制竖直方向间隔
             if(orientation == OrientationHelper.HORIZONTAL && i >= childCount - extra) {
                 isDrawVerticalDivider = false;
             }

             if(isDrawHorizontalDivider) {
                 drawHorizontalDivider(c, parent, i);
             }

             if(isDrawVerticalDivider) {
                 drawVerticalDivider(c, parent, i);
             }
         }
     }

     @Override
     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
         int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
         int orientation = ((GridLayoutManager)parent.getLayoutManager()).getOrientation();
         int position = parent.getChildLayoutPosition(view);
         if(orientation == OrientationHelper.VERTICAL && (position + 1) % spanCount == 0) {
             outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
             return;
         }

         if(orientation == OrientationHelper.HORIZONTAL && (position + 1) % spanCount == 0) {
             outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
             return;
         }

         outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
     }

     /**
      * 绘制竖直间隔线
      *
      * @param canvas
      * @param parent
      *              父布局,RecyclerView
      * @param position
      *              irem在父布局中所在的位置
      */
     private void drawVerticalDivider(Canvas canvas, RecyclerView parent, int position) {
         final View child = parent.getChildAt(position);
         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                 .getLayoutParams();
         final int top = child.getTop() - params.topMargin;
         final int bottom = child.getBottom() + params.bottomMargin + mDivider.getIntrinsicHeight();
         final int left = child.getRight() + params.rightMargin;
         final int right = left + mDivider.getIntrinsicWidth();
         mDivider.setBounds(left, top, right, bottom);
         mDivider.draw(canvas);
     }

     /**
      * 绘制水平间隔线
      *
      * @param canvas
      * @param parent
      *              父布局,RecyclerView
      * @param position
      *              item在父布局中所在的位置
      */
     private void drawHorizontalDivider(Canvas canvas, RecyclerView parent, int position) {
         final View child = parent.getChildAt(position);
         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                 .getLayoutParams();
         final int top = child.getBottom() + params.bottomMargin;
         final int bottom = top + mDivider.getIntrinsicHeight();
         final int left = child.getLeft() - params.leftMargin;
         final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth();
         mDivider.setBounds(left, top, right, bottom);
         mDivider.draw(canvas);
     }
 }

00-Unit_Common综述-RecyclerView封装的更多相关文章

  1. 打造android偷懒神器———RecyclerView的万能适配器

    转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html 很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时 ...

  2. Android 5&period;X新特性之RecyclerView基本解析及无限复用

    说到RecyclerView,相信大家都不陌生,它是我们经典级ListView的升级版,升级后的RecyclerView展现了极大的灵活性.同时内部直接封装了ViewHolder,不用我们自己定义Vi ...

  3. 一篇博客理解Recyclerview的使用

    从Android 5.0开始,谷歌公司推出了RecylerView控件,当看到RecylerView这个新控件的时候,大部分人会首先发出一个疑问,recylerview是什么?为什么会有recyler ...

  4. Android开发——RecyclerView特性以及基本使用方法(一)

    )关于点击事件,没有像ListView那样现成的API,但是自己封装起来也不难,而且我们使用ListView时,如果item中有可点击组件,那么点击事件的冲突也是一个问题,而在RecyclerView ...

  5. RecyclerView底部刷新实现具体解释

    关于RecyclerView底部刷新实现的文章已经非常多了,但大都仅仅介绍了其基本原理和框架,对当中的非常多细节没有交代,无法直接使用. 本文会着重介绍RecyclerView底部刷新实现的一些细节处 ...

  6. 从 ListView 到 RecyclerView 的用法浅析

    文章目录 要走好明天的路,必须记住昨天走过的路,思索今天正在走着的路. ListView,一种在垂直滚动列表中显示条目的视图:RecyclerView,一种在局限的窗口呈现大数据集合的灵活视图.Rec ...

  7. RecyclerView 的简单使用

    自从 Android 5.0 之后,google 推出了一个 RecyclerView 控件,他是 support-v7 包中的新组件,是一个强大的滑动组件,与经典的 ListView 相比,同样拥有 ...

  8. colorPrimaryDark无法改变状态栏颜色

    设置完colorPrimaryDark后,这个颜色是改变状态栏的颜色的, colorPrimary是改变标题栏背景色的 发现状态栏一直是灰色. 然后在布局文件中 AndroidMainifest.xm ...

  9. 《Android群英传》读书笔记 &lpar;5&rpar; 第十一章 搭建云端服务器 &plus; 第十二章 Android 5&period;X新特性详解 &plus; 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

随机推荐

  1. 优化Table View

    优化Table View Table view需要有很好的滚动性能,不然用户会在滚动过程中发现动画的瑕疵. 为了保证table view平滑滚动,确保你采取了以下的措施: 正确使用`reuseIden ...

  2. python之列表、字典、集合

    列表 name = ["Alex","Eenglan","Eric"] print(name[0]) print(name[1]) prin ...

  3. java 请求 google translate

    // */ // ]]> java 请求 google translate Table of Contents 1. 使用Java获取Google Translate结果 1.1. 开发环境设置 ...

  4. 【PHP】iOS推送通知以及反馈服务

    近来项目是完成一个PHP的推送服务器,无论是PHP,APNs还是GCM基本上都是从零开始. 写下一点见解,方便以后继续做代码的搬运工. 因为对PHP跟iOS都不熟悉,可能有错漏...穷孩子没有用过iO ...

  5. T-SQL 脚本

    1.USE语句 USE语句用于设置当前数据库,如果没有USE语句,那么就由执行脚本的任何用户来确定执行脚本时当前数据库是正确的.如果只是一个通用脚本,那么省去USE语句实际上可能更有益.通常,如果在脚 ...

  6. Problem F&colon; 分数类的类型转换

    Description 封装一个分数类Fract,用来处理分数功能和运算,支持以下操作:   1. 构造:传入两个参数n和m,表示n/m:分数在构造时立即转化成最简分数. 2. show()函数:分数 ...

  7. python语言中的AOP利器:装饰器

    一.前言 面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java ...

  8. swust oj 971

    统计利用先序遍历创建的二叉树的深度 10000(ms) 10000(kb) 3331 / 8436 利用先序递归遍历算法创建二叉树并计算该二叉树的深度.先序递归遍历建立二叉树的方法为:按照先序递归遍历 ...

  9. java注解篇

    @SuppressWarnings注解 该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默. 允许您选择性地取消特定代码段(即,类或方法)中的警告.其中的想法是当您看到警告 ...

  10. 记录Newtonsoft&period;Json的日常用法

    最近在做一个使用基于.net mvc 实现前后台传输Json的实例.网上找了一些资料.发现在开发的时候,许多的数据交互都是以Json格式传输的.其中涉及序列化对象的使用的有DataContractJs ...