自学安卓也有一年的时间了,与代码相伴的日子里,苦乐共存。能坚持到现在确实已见到了“往日所未曾见证的风采”。今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也会增加
 
 

下面是笔者封装的代码:虽然比较多,但拷贝进去就能用。好了,综述就到这里。

对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.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群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

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

随机推荐

  1. 深入解析OpenCart的代理类proxy

    1.什么是代理类 代理类指的是连接远程对象或不可见对象的接口,通常被客户端调用来连接真实的服务对象.更准确的定义参见维基百科 2.代理的作用 作为一个包装类,提供额外的功能 延迟加载 在本文讲到的op ...

  2. Mysql编译安装详解

    wget http://mirrors.cnnic.cn/apache/httpd/mysql-5.5.20.tar.gz root@Mysql-server ~]# yum install -y c ...

  3. mysql自带的example测试数据库导入Centos6.5

    1.下载数据库 下载地址: [test数据库] (https://github.com/datacharmer/test_db) 不出意外的话,下载下来是个unzip文件. 2.上传到数据库服务器 r ...

  4. 'NoneType' object is not iterable

    "TypeError: 'NoneType' object is not iterable" 一般是返回值为None同时赋值给了多个变量

  5. Docker 基础技术之 Linux namespace 源码分析

    上篇我们从进程 clone 的角度,结合代码简单分析了 Linux 提供的 6 种 namespace,本篇从源码上进一步分析 Linux namespace,让你对 Docker namespace ...

  6. Redis Cluster 4.0 on CentOS 6.9 搭建

    集群简介 Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation). Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需 ...

  7. dev gridControl 自定义绘制列头颜色

    1.添加事件CustomDrawColumnHeader private void gvw1_CustomDrawColumnHeader(object sender, DevExpress.Xtra ...

  8. 分布式版本管理工具 git常用命令

    Git global setup git config --global user.name "joey" git config --global user.email " ...

  9. 推荐一个c++小巧开源且跨平台的图像解码库

    该图像解码库仅仅三个文件. 图像处理封装: spot.cpp spot.h 解码库实现: spot.c 支持图片文件格式如下: File format Read Write BMP files yes ...

  10. [BZOJ 5093]图的价值

    Description 题库链接 一个带标号的图的价值定义为每个点度数的 \(k\) 次方的和.给定 \(n\) 和 \(k\) ,请计算所有 \(n\) 个点的带标号的简单无向图的价值之和.对 \( ...