原文来自:http://www.cnblogs.com/liuling/p/2015-11-04-01.html
compile 'com.android.support:recyclerview-v7:23.3.0'。如果是eclipse直接导入android-support-v7-recyclerview.jar就可以了。
找到v7下的包,编译的时候出错,可以更改为
- 控制其显示的方式,通过布局管理器LayoutManager
- 控制Item间的间隔(可绘制),通过ItemDecoration
- 控制Item增删的动画,通过ItemAnimator
- 控制点击、长按事件,自己写
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_text" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
/** * Created by Administrator on 2016/9/27. */ public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> { private Context context; private List<String>dataList; private MyOnItemClickListener myOnItemClickListener; /** * 重写构造方法 * @param context 当前activity对象 * @param dataList 数据源 */ public MyRecyclerViewAdapter(Context context, List<String> dataList) { this.context = context; this.dataList = dataList; } /** * 创建viewHolder * @param parent * @param viewType * @return */ @Override public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //加载布局 View view = LayoutInflater.from(context).inflate(R.layout.layout_recyclerview_item,parent,false); //创建viewholder对象,将布局传入 ItemViewHolder viewHolder = new ItemViewHolder(view); return viewHolder; } /** * 绑定viewHolder * @param holder recycleView.ViewHolder的子类 * @param position 当前索引 */ @Override public void onBindViewHolder(final ItemViewHolder holder,final int position) { holder.tv_text.setText(dataList.get(position)); //给每个item设置点击事件 //判断是否存在监听
/** 这里加了判断,itemViewHolder.itemView.hasOnClickListeners() 目的是减少对象的创建,如果已经为view设置了click监听事件,就不用重复设置了,不然每次调用onBindViewHolder方法,都会创建两个监听事件对象,增加了内存的开销 */
if(myOnItemClickListener != null&&!holder.tv_text.hasOnClickListeners()){ holder.tv_text.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //注意:当点击该position的时候,recycleView中默认点击的是在父控件中的位置,当删除数据时,也是删除父布局中的对应索引的位置 //比如:删除点击item4会删除Item4,再点击item6,会删除item7,因为item7在父布局中位置为6,因此推荐使用父类的position myOnItemClickListener.myOnItemClick(v,holder.getLayoutPosition()); } }); holder.tv_text.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { myOnItemClickListener.myOItemLongClick(v,holder.getLayoutPosition()); return true; } }); } } @Override public int getItemCount() { return dataList.size(); } /** * 设置自定义对外暴露的监听 * @param myOnItemClickListener */ public void setMyOnItemClickListener(MyOnItemClickListener myOnItemClickListener){ this.myOnItemClickListener = myOnItemClickListener; } /** * 删除数据 * @param position */ public void deleteData(int position){ dataList.remove(position); //更新当前删除条目的数据 notifyItemRemoved(position); } public void addData(int positon,String data){ dataList.add(positon,data); //只更新当前插入的条目的数据 notifyItemInserted(positon); } /** * 添加数据 * @param list */ public void updateData(List<String> list){ dataList.addAll(list); notifyDataSetChanged(); } class ItemViewHolder extends RecyclerView.ViewHolder{ private TextView tv_text; public ItemViewHolder(View itemView) { super(itemView); tv_text = (TextView) itemView.findViewById(R.id.tv_text); } } public interface MyOnItemClickListener{ void myOnItemClick(View view,int Postion); void myOItemLongClick(View view,int position); } }
可以看到数据适配器与BaseAdapter比较发生了相当大的变化,主要有3个方法:
getItemCount 这个不用说,获取总的条目数
onCreateViewHolder 创建ViewHolder
onBindViewHolder 将数据绑定至ViewHolder
可见,RecyclerView对ViewHolder也进行了一定的封装,但是如果你仔细观察,你会发出一个疑问,ListView里面有个getView返回View为Item的布局,那么这个Item的样子在哪控制?
其实是这样的,我们创建的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View相当于我们ListView getView中的convertView (即:我们需要inflate的item布局需要传入)。
还有一点,ListView中convertView是复用的,在RecyclerView中,是把ViewHolder作为缓存的单位了,然后convertView作为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这个方法变为了onCreateViewHolder。有兴趣的自己打印下Log,测试下
main方法:
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private List<String> dataList = new ArrayList<String>(); private MyRecyclerViewAdapter recyclerViewAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化控件 recyclerView = (RecyclerView) findViewById(R.id.recyclerView); /** 设置布局管理器,listview风格则设置为LinearLayoutManager gridview风格则设置为GridLayoutManager pu瀑布流风格的设置为StaggeredGridLayoutManager */ //默认竖直滚动 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(linearLayoutManager); //初始化数据 initData(); //创建适配器 recyclerViewAdapter = new MyRecyclerViewAdapter(this,dataList); //设置适配器 recyclerView.setAdapter(recyclerViewAdapter); //设置自定义点击监听 recyclerViewAdapter.setMyOnItemClickListener(new MyRecyclerViewAdapter.MyOnItemClickListener() { //点击item的时候调用 @Override public void myOnItemClick(View view, int Postion) { Toast.makeText(MainActivity.this, dataList.get(Postion), Toast.LENGTH_SHORT).show(); recyclerViewAdapter.deleteData(Postion); } //长按item的时候调用 @Override public void myOItemLongClick(View view, int position) { Toast.makeText(MainActivity.this,"长按--"+dataList.get(position), Toast.LENGTH_SHORT).show(); recyclerViewAdapter.addData(position,"我是新来的"); } }); } private void initData() { for (int i = 0; i < 30; i++) { dataList.add((i+1)+"条数据"); } } }
效果如下:
点击时:
点击后:
长按后:
ItemDecoration
我们可以通过该方法添加分割线: mRecyclerView.addItemDecoration()
RecyclerView.ItemDecoration
的实现类
package fanggao.qf.recycleviewlistview; 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.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; /** * Created by Administrator on 2016/9/27. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { Log.v("recyclerview - itemdecoration", "onDraw()"); if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }
该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider
作为Item间的分割线,并且支持横向和纵向
在源代码上添加一句
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
效果:
该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况
续:recycleView的一些常用属性:
recyclerView.getChildCount()只是获取的是可见的item个数
recyclerView.getLayoutManager().getItemCount()获取的是所有的item的个数
recyclerView.getChildAt(int position) 获取某个位置的view
recyclerView.getChildAdapterPosition(View view) 获取某个view的位置
可通过上面几个属性,在recycleView的滚动监听中实现自定义的recycleView的上拉加载和下拉刷新
具体见转载请标明出处:
http://blog.csdn.net/lmj623565791/article/details/45059587;
本文出自:【张鸿洋的博客】