自学安卓也有一年的时间了,与代码相伴的日子里,苦乐共存。能坚持到现在确实已见到了“往日所未曾见证的风采”。今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. phalcon环境的搭建和dll扩展下载与选择

    phalcon需要下载一个扩展的dll文件才能运行项目 其中需要注意dll放在一个php扩展目录中windows下php/ext/,还需要在两个Php.ini文件中增加扩展说明,一般只需要更改 D:\ ...

  2. ESP8266 wifi 模块配置,Wechat+APP控制实现

    首先刷入安信可的AiCloud 2.0 SDK文件,AiCloud 2.0具体信息参见AiCloud 1.0 和AiCloud 2.0对比 APP见如下二维码下载. 1.安信可AiCloud 2.0 ...

  3. 如何用UPA优化性能?先读懂这份报告!

    一.概述 打开一份UPA报告时,最先看到的就是概述页面,这也是我们推荐用户第一时间关注的页面.概述页面一开始会列出测试的基本信息,并根据腾讯游戏的性能标准,给出本次测试的结果(通过,不通过和警告): ...

  4. node express将请求重定向为https

    项目开发时,由于服务器只接受https请求(运维说了算...),所以在生产环境时,要把所有http请求全都重定向为https,具体操作是在app.js文件里加入以下代码: var express = ...

  5. SQL Server数据库优化的10多种方法

    巧妙优化sql server数据库的几种方法,在实际操作中导致查询速度慢的原因有很多,其中最为常见有以下的几种:没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷). I/O吞吐量小, ...

  6. Java基础语法<五> 大数值BigInteger BigDecimal

    笔记整理 来源于<Java核心技术卷 I > <Java编程思想> 如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中的两个很有平有用的类:BigIn ...

  7. jvm学习记录-对象的创建、对象的内存布局、对象的访问定位

    简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以Hot ...

  8. 学习React系列(九)——高阶函数

    定义:高阶组件就是一个函数,且该函数接收一个组件作为参数,并返回一个新的组件. (上一篇已经说过了高阶组件可以用来解决交叉问题) 一.不要改变原始组件,使用组合 class A extends Rea ...

  9. 重拾Python(5):数据读取

    本文主要对Python如何读取数据进行总结梳理,涵盖从文本文件,尤其是excel文件(用于离线数据探索分析),以及结构化数据库(以Mysql为例)中读取数据等内容. 约定: import numpy ...

  10. dropzone.js使用实践

    官网地址:http://www.dropzonejs.com/ 一,它是什么: DropzoneJS is an open source library that provides drag'n'dr ...