自学安卓也有一年的时间了,与代码相伴的日子里,苦乐共存。能坚持到现在确实已见到了“往日所未曾见证的风采”。今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. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  2. Java服务器端生成报告文档:使用SQL Server Report Service(SSRS)

    SQL Server Report Service(SSRS)提供了Asp.Net和WinForm两类客户端组件封装,因此使用C#实现SSRS报表的导出功能,仅需要使用相应的组件即可. Java操作S ...

  3. jenkins简单安装及配置(Windows环境)

    jenkins是一款跨平台的持续集成和持续交付.基于Java开发的开源软件,提供任务构建,持续集成监控的功能,可以使开发测试人员更方便的构建软件项目,提高工作效率. Windows平台下,一般安装方法 ...

  4. 用Vue.js开发微信小程序:开源框架mpvue解析

    前言 mpvue 是一款使用 Vue.js 开发微信小程序的前端框架.使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力.如果想将 H5 项目改造为小程 ...

  5. Python内置函数(30)——super

    英文文档: super([type[, object-or-type]]) Return a proxy object that delegates method calls to a parent ...

  6. 新概念英语(1-31)Where's Sally?

    新概念英语(1-31)Where's Sally? Is the cat climbing the tree ? A:Where is Sally, Jack ? B:She is in the ga ...

  7. Linux实战案例(5)关闭Centos的防火墙

    1.检查防火墙的状态 [root@LxfN1 ~]# service iptables status表格:filterChain INPUT (policy ACCEPT)num target pro ...

  8. 1.7 理解dropout

    Dropout为什么有正则化的作用? 下面来直观理解一下. 上面讲到,dropout每次迭代都会让一部分神经元失活,这样使得神经网络会比原始的神经网络规模变小,因此采用一个较小神经网络好像和使用正则化 ...

  9. java 面向对象编程。。。。

    经过一周的学习(java),总结了许多,对java的理解,java的类型,运用,安装,基础语法,变量,常量,表达式,语句 java从C语言中继承了大量语言特性.java面向对象编程的基本特征,包括继承 ...

  10. nginx location的命中过程

    1 先判断精准命中,立即返回结果并结束解析过程 2 判断普通命中,如果有多个命中,"记录"下"最长"的命中结果(注意:记录但不结束,最长的为准) 3 继续判断正 ...