当前位置: 移动技术网 > IT编程>移动开发>Android > 00-Unit_Common综述-RecyclerView封装

00-Unit_Common综述-RecyclerView封装

2018年04月25日  | 移动技术网IT编程  | 我要评论

天空侵犯,曾贤哥,白色污染图片

自学安卓也有一年的时间了,与代码相伴的日子里,苦乐共存。能坚持到现在确实已见到了“往日所未曾见证的风采”。今2018年4月24日,决定用一个案例: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
  1 package utils.ev.recyclerview;
  2 
  3 import android.graphics.Bitmap;
  4 import android.support.v7.widget.RecyclerView;
  5 import android.util.SparseArray;
  6 import android.view.View;
  7 import android.widget.ImageView;
  8 import android.widget.TextView;
  9 
 10 import com.bumptech.glide.Glide;
 11 import com.bumptech.glide.load.engine.DiskCacheStrategy;
 12 
 13 import utils.ui.UIUtils;
 14 
 15 /**
 16  * 作者:张风捷特烈
 17  * 时间:2018/4/10:14:22
 18  * 邮箱:1981462002@qq.com
 19  * 说明:View的持有人
 20  */
 21 public class MyRVHolder extends RecyclerView.ViewHolder {
 22 
 23     //键值对中键是int类型使用SparseArray比map更好
 24     private SparseArray<View> mViews;//持有的所有View集合
 25     private View mItemView;//Item的
 26 
 27     public MyRVHolder(View itemView) {
 28 
 29         super(itemView);
 30         mItemView = itemView;
 31         mViews = new SparseArray<>();
 32     }
 33 
 34     /**
 35      * 获取pos
 36      *
 37      * @return
 38      */
 39     public int getPos() {
 40         return this.getLayoutPosition();
 41     }
 42 
 43     /**
 44      * 通过viewId获取控件
 45      *
 46      * @param viewId
 47      * @param <T>
 48      * @return
 49      */
 50     public <T extends View> T getView(int viewId) {
 51         View view = mViews.get(viewId);
 52         if (view == null) {
 53             view = mItemView.findViewById(viewId);
 54             mViews.put(viewId, view);//以id为键,view为值
 55         }
 56         return (T) view;
 57     }
 58 
 59     public View getItemView() {
 60         return mItemView;
 61     }
 62 
 63     /**
 64      * 设置item背景颜色
 65      */
 66     public MyRVHolder setColor(int color) {
 67         mItemView.setBackgroundColor(color);
 68         return this;
 69     }
 70 
 71     /**
 72      * 设置TextView文本方法
 73      *
 74      * @param viewId
 75      * @param text
 76      * @return
 77      */
 78     public MyRVHolder setText(int viewId, String text) {
 79         TextView view = getView(viewId);
 80         view.setText(text);
 81         return this;
 82     }
 83 
 84     /**
 85      * 通过资源id设置ImageView图片
 86      * @param viewId
 87      * @param resId
 88      * @return
 89      */
 90     public MyRVHolder setImageViewRes(int viewId, int resId) {
 91         ImageView view = getView(viewId);
 92         view.setImageResource(resId);
 93         return this;
 94     }
 95 
 96     /**
 97      * 通过Bitmap设置ImageView图片
 98      * @param viewId
 99      * @param bitmap
100      * @return
101      */
102     public MyRVHolder setImageViewBitmap(int viewId, Bitmap bitmap) {
103         ImageView view = getView(viewId);
104         view.setImageBitmap(bitmap);
105         return this;
106     }
107 
108     /**
109      * 通过url设置图片
110      * @param viewId
111      * @param url
112      * @return
113      */
114     public MyRVHolder setImageViewUrl(int viewId, String url) {
115         ImageView view = getView(viewId);
116         //此处使用Glide进行Url类型图片的加载,如果未添加Glide依赖会报错
117         //依赖: implementation 'com.github.bumptech.glide:glide:3.7.0'
118         Glide.with(UIUtils.getContext())
119                 .load(url)
120                 .skipMemoryCache(false)
121                 .diskCacheStrategy(DiskCacheStrategy.SOURCE)
122                 .into(view);
123 
124         return this;
125     }
126 
127     /////////////////////可继续拓展完善,添加更多方法//////////////////////
128 }
  1 package utils.ev.recyclerview;
  2 
  3 import android.support.v7.widget.RecyclerView;
  4 import android.view.View;
  5 import android.view.ViewGroup;
  6 
  7 import java.util.List;
  8 
  9 import utils.ui.UIUtils;
 10 
 11 /**
 12  * 作者:张风捷特烈
 13  * 时间:2018/4/10:14:28
 14  * 邮箱:1981462002@qq.com
 15  * 说明:RecyclerView的Adapter封装类
 16  */
 17 public abstract class MyRVAdapter<T> extends RecyclerView.Adapter<MyRVHolder> {
 18     protected List<T> mDatas;
 19     protected int mItemId;
 20     private View mItemView;
 21 
 22     public MyRVAdapter(List<T> datas, int itemId) {
 23         mDatas = datas;
 24         mItemId = itemId;
 25     }
 26 
 27     @Override
 28     public MyRVHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 29         mItemView = UIUtils.inflate(mItemId);
 30         final MyRVHolder myRVHolder = new MyRVHolder(mItemView);
 31         //点击事件方式
 32         mItemView.setOnClickListener(new View.OnClickListener() {
 33             @Override
 34             public void onClick(View v) {//使用回调实现点击监听
 35                 if (mOnRvItemClickListener != null) {
 36                     mOnRvItemClickListener.OnRvItemClick(v, myRVHolder.getPos());
 37 
 38                 }
 39             }
 40         });
 41 
 42         return myRVHolder;
 43     }
 44 
 45     @Override
 46     public void onBindViewHolder(MyRVHolder holder, int position) {
 47 
 48         setDatas(holder, mDatas.get(position), position);
 49 
 50     }
 51 
 52     @Override
 53     public int getItemCount() {
 54         return mDatas.size();
 55     }
 56 
 57     /**
 58      * 抽象方法,通过holder可对各控件进行操作
 59      *
 60      * @param holder   View的持有人
 61      * @param data     数据
 62      * @param position 点击位置
 63      */
 64     public abstract void setDatas(MyRVHolder holder, T data, int position);
 65 
 66 ///////////////////////////////////////////////////////////
 67 
 68     /**
 69      * 添加item
 70      *
 71      * @param i
 72      * @param aNew
 73      */
 74     public void addData(int i, T aNew) {
 75         mDatas.add(i, aNew);
 76         notifyItemInserted(i);//刷新数据
 77     }
 78 
 79     /**
 80      * 删除item
 81      *
 82      * @param i
 83      */
 84     public void deleteData(int i) {
 85         mDatas.remove(i);
 86         notifyItemRemoved(i);//刷新数据
 87     }
 88 
 89     public View getItemView() {
 90         return mItemView;
 91     }
 92 
 93     /////////////////为RecyclerView设置点击监听接口/////////////////////////
 94     /**
 95      * 为RecyclerView设置点击监听接口
 96      */
 97     public interface OnRvItemClickListener {
 98         void OnRvItemClick(View v, int pos);//item被点击的时候回调方法
 99     }
100 
101     /**
102      * 声明监听器接口对象
103      */
104     private OnRvItemClickListener mOnRvItemClickListener;
105 
106     /**
107      * 设置RecyclerView某个的监听方法
108      *
109      * @param onRvItemClickListener
110      */
111     public void setOnRvItemClickListener(OnRvItemClickListener onRvItemClickListener) {
112         mOnRvItemClickListener = onRvItemClickListener;
113     }
114 }

这样可以使用了,不过为了添加分割线,还有免去写一些初始化的设置方法,把其封装在我的UiUtils中,静态方法如下:
 
 
 1 ////////////////////////设置RecyclerView/////////////////////////////////////////
 2     public static final int GRIDVIEW = 0;
 3     public static final int LISTVIEW = 1;
 4     public static final int PULL = 2;
 5 
 6     /**
 7      *
 8      * @param rv  RecyclerView
 9      * @param count count 数量  LISTVIEW可随意
10      * @param style 模式 GRIDVIEW  LISTVIEW  PULL
11      * @param ctx  上下文
12      */
13     public static GridLayoutManager setStyle4RV(RecyclerView rv, int count, int style,Context ctx) {
14         switch (style) {
15             case GRIDVIEW://GridView类型
16                 rv.addItemDecoration(new MyDividerItemDecoration(ctx));//设置分割线
17                 GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), count, GridLayoutManager.VERTICAL, false);
18                 rv.setLayoutManager(gridLayoutManager);
19                 return gridLayoutManager;
20             case LISTVIEW://ListView类型
21                 rv.addItemDecoration(new SampleDivider(ctx));
22                 rv.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
23                 return null;
24             case PULL://瀑布流类型
25                 rv.addItemDecoration(new MyDividerItemDecoration(ctx));
26                 rv.setLayoutManager(new StaggeredGridLayoutManager(count, StaggeredGridLayoutManager.VERTICAL));
27                 return null;
28         }
29         return null;
30     }
MyDividerItemDecoration 分割线
  1 package utils.ev.recyclerview;
  2 
  3 import android.content.Context;
  4 import android.content.res.TypedArray;
  5 import android.graphics.Canvas;
  6 import android.graphics.Rect;
  7 import android.graphics.drawable.Drawable;
  8 import android.support.v7.widget.GridLayoutManager;
  9 import android.support.v7.widget.OrientationHelper;
 10 import android.support.v7.widget.RecyclerView;
 11 import android.view.View;
 12 
 13 
 14 public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
 15 
 16     private static final int[] ATTRS = new int[]{
 17             android.R.attr.listDivider
 18     };
 19 
 20     /**
 21      * 用于绘制间隔样式
 22      */
 23     private Drawable mDivider;
 24 
 25     public MyDividerItemDecoration(Context context) {
 26         // 获取默认主题的属性
 27         final TypedArray a = context.obtainStyledAttributes(ATTRS);
 28         mDivider = a.getDrawable(0);
 29         a.recycle();
 30     }
 31 
 32 
 33     @Override
 34     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
 35         // 绘制间隔,每一个item,绘制右边和下方间隔样式
 36         int childCount = parent.getChildCount();
 37         int spanCount = ((GridLayoutManager)parent.getLayoutManager()).getSpanCount();
 38         int orientation = ((GridLayoutManager)parent.getLayoutManager()).getOrientation();
 39         boolean isDrawHorizontalDivider = true;
 40         boolean isDrawVerticalDivider = true;
 41         int extra = childCount % spanCount;
 42         extra = extra == 0 ? spanCount : extra;
 43         for(int i = 0; i < childCount; i++) {
 44             isDrawVerticalDivider = true;
 45             isDrawHorizontalDivider = true;
 46             // 如果是竖直方向,最右边一列不绘制竖直方向的间隔
 47             if(orientation == OrientationHelper.VERTICAL && (i + 1) % spanCount == 0) {
 48                 isDrawVerticalDivider = false;
 49             }
 50 
 51             // 如果是竖直方向,最后一行不绘制水平方向间隔
 52             if(orientation == OrientationHelper.VERTICAL && i >= childCount - extra) {
 53                 isDrawHorizontalDivider = false;
 54             }
 55 
 56             // 如果是水平方向,最下面一行不绘制水平方向的间隔
 57             if(orientation == OrientationHelper.HORIZONTAL && (i + 1) % spanCount == 0) {
 58                 isDrawHorizontalDivider = false;
 59             }
 60 
 61             // 如果是水平方向,最后一列不绘制竖直方向间隔
 62             if(orientation == OrientationHelper.HORIZONTAL && i >= childCount - extra) {
 63                 isDrawVerticalDivider = false;
 64             }
 65 
 66             if(isDrawHorizontalDivider) {
 67                 drawHorizontalDivider(c, parent, i);
 68             }
 69 
 70             if(isDrawVerticalDivider) {
 71                 drawVerticalDivider(c, parent, i);
 72             }
 73         }
 74     }
 75 
 76     @Override
 77     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
 78         int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
 79         int orientation = ((GridLayoutManager)parent.getLayoutManager()).getOrientation();
 80         int position = parent.getChildLayoutPosition(view);
 81         if(orientation == OrientationHelper.VERTICAL && (position + 1) % spanCount == 0) {
 82             outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
 83             return;
 84         }
 85 
 86         if(orientation == OrientationHelper.HORIZONTAL && (position + 1) % spanCount == 0) {
 87             outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
 88             return;
 89         }
 90 
 91         outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
 92     }
 93 
 94     /**
 95      * 绘制竖直间隔线
 96      *
 97      * @param canvas
 98      * @param parent
 99      *              父布局,RecyclerView
100      * @param position
101      *              irem在父布局中所在的位置
102      */
103     private void drawVerticalDivider(Canvas canvas, RecyclerView parent, int position) {
104         final View child = parent.getChildAt(position);
105         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
106                 .getLayoutParams();
107         final int top = child.getTop() - params.topMargin;
108         final int bottom = child.getBottom() + params.bottomMargin + mDivider.getIntrinsicHeight();
109         final int left = child.getRight() + params.rightMargin;
110         final int right = left + mDivider.getIntrinsicWidth();
111         mDivider.setBounds(left, top, right, bottom);
112         mDivider.draw(canvas);
113     }
114 
115     /**
116      * 绘制水平间隔线
117      *
118      * @param canvas
119      * @param parent
120      *              父布局,RecyclerView
121      * @param position
122      *              item在父布局中所在的位置
123      */
124     private void drawHorizontalDivider(Canvas canvas, RecyclerView parent, int position) {
125         final View child = parent.getChildAt(position);
126         final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
127                 .getLayoutParams();
128         final int top = child.getBottom() + params.bottomMargin;
129         final int bottom = top + mDivider.getIntrinsicHeight();
130         final int left = child.getLeft() - params.leftMargin;
131         final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth();
132         mDivider.setBounds(left, top, right, bottom);
133         mDivider.draw(canvas);
134     }
135 }

 


如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网