什么是RecyclerView
RecyclerView是Android 5.0 materials design中的组件之一,相应的还有CardView、Palette等。看名字我们就能看出一点端倪,没错,它主要的特点就是复用。我们知道,Listview中的Adapter中可以实现ViewHolder的复用。RecyclerView提供了一个耦合度更低的方式来复用ViewHolder,并且可以轻松的实现ListView、GridView以及瀑布流的效果。
RecyclerView的用法
首先我们要gradle的依赖库中添加 compile 'com.android.support:recyclerview-v7:21.+' 。如果是eclipse直接导入android-support-v7-recyclerview.jar就可以了。
1 /**
2 * 设置Adapter
3 */
4 mRecyclerView.setAdapter(mListAdapter);
5 /**
6 * 设置布局管理器
7 */
8 mRecyclerView.setLayoutManager(linearLayoutManager);
9 /**
10 * 设置item分割线
11 */
12 mRecyclerView.addItemDecoration(itemDecoration);
13 /**
14 * 设置item动画
15 */
16 mRecyclerView.setItemAnimator(new DefaultItemAnimator());
使用RecyclerView,基本上要上面四步。相比ListView只需设置Adapter而言,RecyclerView的使用看起来似乎要复杂一些。但是它的可定制性更高了,你可以自己定制自己的分割线样式或者是item的的动画。
下面我们看下如何使用RecyclerView简单实现ListView的效果。
activity:
1 package com.bbk.lling.recyclerview;
2
3 import android.support.v7.app.ActionBarActivity;
4 import android.os.Bundle;
5 import android.support.v7.widget.DefaultItemAnimator;
6 import android.support.v7.widget.LinearLayoutManager;
7 import android.support.v7.widget.RecyclerView;
8 import android.view.Menu;
9 import android.view.MenuItem;
10 import android.view.View;
11 import android.widget.Toast;
12
13 import java.util.ArrayList;
14 import java.util.List;
15
16 /**
17 * @Class: ListLayoutActivity
18 * @Description: RecycleView实现listview的功能
19 * @author: lling(www.liuling123.com)
20 * @Date: 2015/10/29
21 */
22 public class ListLayoutActivity extends ActionBarActivity {
23
24 private RecyclerView mRecyclerView;
25 private ListAdapter mListAdapter;
26 private List<String> mDatas;
27
28 @Override
29 protected void onCreate(Bundle savedInstanceState) {
30 super.onCreate(savedInstanceState);
31 setContentView(R.layout.activity_list_layout);
32 initData();
33 mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
34 mListAdapter = new ListAdapter(this, mDatas);
35 mListAdapter.setOnItemClickListener(new ListAdapter.OnItemClickListener() {
36 @Override
37 public void onItemClick(View view, int position) {
38 Toast.makeText(ListLayoutActivity.this, "Click" + mDatas.get(position), Toast.LENGTH_SHORT).show();
39 }
40
41 @Override
42 public void onItemLongClick(View view, int position) {
43 mListAdapter.remove(position); //remove the item
44 Toast.makeText(ListLayoutActivity.this, "LongClick" + mDatas.get(position), Toast.LENGTH_SHORT).show();
45 }
46 });
47 mRecyclerView.setAdapter(mListAdapter);
48 /**
49 * 设置布局管理器,listview风格则设置为LinearLayoutManager
50 * gridview风格则设置为GridLayoutManager
51 * pu瀑布流风格的设置为StaggeredGridLayoutManager
52 */
53 mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
54 // 设置item分
55 mRecyclerView.addItemDecoration(new ListItemDecoration(this, LinearLayoutManager.VERTICAL));
56 // 设置item动画
57 mRecyclerView.setItemAnimator(new DefaultItemAnimator());
58
59 }
60
61 @Override
62 public boolean onCreateOptionsMenu(Menu menu) {
63 getMenuInflater().inflate(R.menu.menu_list_layout, menu);
64 return true;
65 }
66
67 @Override
68 public boolean onOptionsItemSelected(MenuItem item) {
69 switch (item.getItemId()) {
70 case R.id.add_first:
71 mListAdapter.add(0, "add first");
72 break;
73 case R.id.add_last:
74 mListAdapter.add(mListAdapter.getItemCount(), "add last");
75 break;
76 case R.id.remove_first:
77 String value = mListAdapter.remove(0);
78 Toast.makeText(ListLayoutActivity.this, "remove:" + value, Toast.LENGTH_SHORT).show();
79 break;
80 case R.id.remove_last:
81 String value1 = mListAdapter.remove(mListAdapter.getItemCount()-1);
82 Toast.makeText(ListLayoutActivity.this, "remove:" + value1, Toast.LENGTH_SHORT).show();
83 break;
84 case R.id.horizontal:
85 mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
86 mRecyclerView.addItemDecoration(new ListItemDecoration(this, LinearLayoutManager.HORIZONTAL));
87 break;
88 case R.id.vertical:
89 mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
90 mRecyclerView.addItemDecoration(new ListItemDecoration(this, LinearLayoutManager.VERTICAL));
91 break;
92 }
93 return super.onOptionsItemSelected(item);
94 }
95
96 /* ==========This Part is not necessary========= */
97
98 /**
99 * Create datas
100 */
101 protected void initData() {
102 mDatas = new ArrayList<String>();
103 for (int i = 0; i < 100; i++) {
104 mDatas.add(String.valueOf(i));
105 }
106 }
107
108 /* ==========This Part is not necessary========= */
109 }
activity布局:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <android.support.v7.widget.RecyclerView
7 android:id="@+id/recyclerview"
8 android:layout_width="match_parent"
9 android:layout_height="match_parent" />
10
11 </RelativeLayout>
Adapter:
1 package com.bbk.lling.recyclerview;
2
3 import android.annotation.SuppressLint;
4 import android.content.Context;
5 import android.support.v7.widget.RecyclerView;
6 import android.util.Log;
7 import android.view.LayoutInflater;
8 import android.view.View;
9 import android.view.ViewGroup;
10 import android.widget.TextView;
11
12 import java.util.List;
13
14 /**
15 * @Class: ListAdapter
16 * @Description: 数据适配器
17 * @author: lling(www.liuling123.com)
18 * @Date: 2015/10/29
19 */
20 public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ItemViewHolder> {
21
22 private List<String> mDatas;
23 private LayoutInflater mInflater;
24 private OnItemClickListener mOnItemClickListener;
25
26 public ListAdapter(Context context, List<String> mDatas) {
27 this.mDatas = mDatas;
28 mInflater = LayoutInflater.from(context);
29 }
30
31 @Override
32 public int getItemCount() {
33 return mDatas.size();
34 }
35
36 @SuppressLint("NewApi")
37 @Override
38 public void onBindViewHolder(final ItemViewHolder itemViewHolder, final int i) {
39 itemViewHolder.mTextView.setText(mDatas.get(i));
40 if(mOnItemClickListener != null) {
41 /**
42 * 这里加了判断,itemViewHolder.itemView.hasOnClickListeners()
43 * 目的是减少对象的创建,如果已经为view设置了click监听事件,就不用重复设置了
44 * 不然每次调用onBindViewHolder方法,都会创建两个监听事件对象,增加了内存的开销
45 */
46 if(!itemViewHolder.itemView.hasOnClickListeners()) {
47 Log.e("ListAdapter", "setOnClickListener");
48 itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
49 @Override
50 public void onClick(View v) {
51 int pos = itemViewHolder.getPosition();
52 mOnItemClickListener.onItemClick(v, pos);
53 }
54 });
55 itemViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
56 @Override
57 public boolean onLongClick(View v) {
58 int pos = itemViewHolder.getPosition();
59 mOnItemClickListener.onItemLongClick(v, pos);
60 return true;
61 }
62 });
63 }
64 }
65 }
66
67 @Override
68 public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
69 /**
70 * 使用RecyclerView,ViewHolder是可以复用的。这根使用ListView的VIewHolder复用是一样的
71 * ViewHolder创建的个数好像是可见item的个数+3
72 */
73 Log.e("ListAdapter", "onCreateViewHolder");
74 ItemViewHolder holder = new ItemViewHolder(mInflater.inflate(
75 R.layout.item_layout, viewGroup, false));
76 return holder;
77 }
78
79 /**
80 * 向指定位置添加元素
81 * @param position
82 * @param value
83 */
84 public void add(int position, String value) {
85 if(position > mDatas.size()) {
86 position = mDatas.size();
87 }
88 if(position < 0) {
89 position = 0;
90 }
91 mDatas.add(position, value);
92 /**
93 * 使用notifyItemInserted/notifyItemRemoved会有动画效果
94 * 而使用notifyDataSetChanged()则没有
95 */
96 notifyItemInserted(position);
97 }
98
99 /**
100 * 移除指定位置元素
101 * @param position
102 * @return
103 */
104 public String remove(int position) {
105 if(position > mDatas.size()-1) {
106 return null;
107 }
108 String value = mDatas.remove(position);
109 notifyItemRemoved(position);
110 return value;
111 }
112
113
114 public void setOnItemClickListener(OnItemClickListener mOnItemClickListener) {
115 this.mOnItemClickListener = mOnItemClickListener;
116 }
117
118 /**
119 * 处理item的点击事件和长按事件
120 */
121 interface OnItemClickListener {
122 public void onItemClick(View view, int position);
123 public void onItemLongClick(View view, int position);
124 }
125
126 class ItemViewHolder extends RecyclerView.ViewHolder {
127
128 private TextView mTextView;
129
130 public ItemViewHolder(View itemView) {
131 super(itemView);
132 mTextView = (TextView) itemView.findViewById(R.id.textview);
133 }
134 }
135
136 }
这里值得注意的是,RecyclerView并没有提供setOnItemClickListener方法来设置item的点击事件,所以这里我们自己来实现item的点击事件,这点很坑爹有木有?没有就自己设置呗!上面代码121-124定义了一个点击接口。然后给Adapter设置定义的接口对象,然后在onBindViewHolder中为每个holder设置点击事件就行了。但是有一点得注意,因为只要滑动RecyclerView,onBindViewHolder就会不停的调用,如果不加判断的话,则会不停的创建新的点击事件对象,浪费内存,所以在设置点击事件之前需要判断一下是否已经设置过了(如上面代码46行),如果设置过了就不需要创建了。
item的布局:
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="match_parent">
5 <TextView
6 android:id="@+id/textview"
7 android:layout_width="wrap_content"
8 android:layout_height="48dp"
9 android:minWidth="48dp"
10 android:gravity="center"
11 android:layout_centerInParent="true"
12 android:text="XXX"/>
13 </RelativeLayout>
item分割线:
1 package com.bbk.lling.recyclerview;
2
3 import android.content.Context;
4 import android.graphics.Canvas;
5 import android.graphics.Rect;
6 import android.graphics.drawable.Drawable;
7 import android.support.v7.widget.LinearLayoutManager;
8 import android.support.v7.widget.RecyclerView;
9 import android.view.View;
10
11 /**
12 * @Class: ListItemDecoration
13 * @Description: listview的item分割线
14 * @author: lling(www.liuling123.com)
15 * @Date: 2015/10/29
16 */
17 public class ListItemDecoration extends RecyclerView.ItemDecoration {
18
19 private Drawable mDrawable;
20
21 private final static int DEFAULT_ORENTATION = LinearLayoutManager.VERTICAL;
22
23 private int mOrientation;
24
25 public ListItemDecoration(Context context, int orientation) {
26 if(orientation != LinearLayoutManager.HORIZONTAL && orientation != LinearLayoutManager.VERTICAL) {
27 this.mOrientation = DEFAULT_ORENTATION;
28 } else {
29 this.mOrientation = orientation;
30 }
31 mDrawable = context.getResources().getDrawable(R.drawable.divider);
32 }
33
34 @Override
35 public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
36 if(mOrientation == LinearLayoutManager.HORIZONTAL) {
37 drawHorizontal(c, parent);
38 } else {
39 drawVertical(c, parent);
40 }
41 }
42
43 private void drawHorizontal(Canvas c, RecyclerView parent) {
44 int top = parent.getPaddingTop();
45 int bottom = parent.getHeight() - parent.getPaddingBottom();
46
47 int childCount = parent.getChildCount();
48 for (int i = 0; i < childCount; i++) {
49 View child = parent.getChildAt(i);
50 RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
51 .getLayoutParams();
52 int left = child.getRight() + params.rightMargin;
53 int right = left + mDrawable.getIntrinsicHeight();
54 mDrawable.setBounds(left, top, right, bottom);
55 mDrawable.draw(c);
56 }
57 }
58
59 private void drawVertical(Canvas c, RecyclerView parent) {
60 int left = parent.getPaddingLeft();
61 int right = parent.getWidth() - parent.getPaddingRight();
62
63 int childCount = parent.getChildCount();
64 for (int i = 0; i < childCount; i++) {
65 View child = parent.getChildAt(i);
66 android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
67 RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
68 .getLayoutParams();
69 int top = child.getBottom() + params.bottomMargin;
70 int bottom = top + mDrawable.getIntrinsicHeight();
71 mDrawable.setBounds(left, top, right, bottom);
72 mDrawable.draw(c);
73 }
74 }
75
76 @Override
77 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
78 super.getItemOffsets(outRect, view, parent, state);
79 }
80 }
divider.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
3 <size android:height="1dp" android:width="1dp"/>
4 <!--<solid android:color="#e0e0e0"/>-->
5 <solid android:color="#ff0000"/>
6 </shape>
好了,ListView的效果已经实现了,看下效果图
RecyclerView实现GridView以及瀑布流效果的代码这里就不贴出来了,demo源码里面有,需要的可以下载看看。
demo源码下载:https://github.com/liuling07/RecyclerView
我喜欢,驾驭着代码在风驰电掣中创造完美!我喜欢,操纵着代码在随必所欲中体验生活!我喜欢,书写着代码在时代浪潮中完成经典!每一段新的代码在我手中诞生对我来说就象观看刹那花开的感动!