Android RecyclerView的使用
RecyclerView是什么?
RecyclerView是一种新的视图组件,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。
在开发RecyclerView时充分考虑了扩展性,因此用它可以创建想到的任何种类的的布局。但在使用上也稍微有些不便。这就是Android——要完成一件事情总不是那么容易。
整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
RecyclerView可以实现以下功能:
ListView的功能
GridView的功能
横向ListView的功能
横向ScrollView的功能
瀑布流效果
便于添加Item增加和移除动画
基本使用
引入官方提供的V7包
main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".MainActivity" tools:showIn="@layout/activity_main"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </RelativeLayout>
在java代码中的声明和普通控件是一样的
recyclerView = (RecyclerView) findViewById(R.id.recyclerview); recyclerView.setLayoutManager(new GridLayoutManager(this,2)); recyclerView.setAdapter(adapter);
setLayoutManager需要一个LayoutManager,这个类有三个实现,分别是:
1.LinearLayoutManager 线性管理器,支持横向、纵向
2.GridLayoutManager 网格布局管理器
3.StaggeredGridLayoutManager 瀑布就式布局管理器
上边的代码使用的是GridLayoutManager展示一个两列的网格布局效果;
再来说说adapter,RecyclerView包含了一种新型适配器,它也需要使用ViewHolder,使用时需要重写两个主要方法:一个用来展现视图和它的持有者的onCreateViewHolder(ViewGroup parent,
int
viewType)
,一个用来把数据绑定到视图上的onBindViewHolder(ViewHolder holder,
int
position)
。这么做的好处是,onCreateViewHolder
只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。
adapter代码:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.myViewHolder> { private Context context; private List<String> mDatas; public RecyclerAdapter(Context context, List<String> mDatas) { super(); this.context = context; this.mDatas = mDatas; } @Override public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { myViewHolder holder = new myViewHolder(LayoutInflater.from(context).inflate(R.layout.item_home, parent, false)); return holder; } @Override public void onBindViewHolder(final myViewHolder holder, int position) { holder.tv.setText(mDatas.get(position)); } @Override public int getItemCount() { return mDatas.size(); } class myViewHolder extends RecyclerView.ViewHolder { TextView tv; public myViewHolder(View itemView) { super(itemView); tv = (TextView) itemView.findViewById(R.id.pos); } } }
item代码:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pos" android:layout_width="144dip" android:layout_height="72dip" android:background="@color/colorPrimary" android:gravity="center" android:layout_margin="4dip" android:textColor="#ffffff" />
之所以设置一个4dp的margin是因为RecyclerView并没有为我们提供一个想listview那样的设置分割线的属性,所以可以在item中设置一个margin,当然你其实可以通过RecyclerView的addItemDecoration方法去自定义一个分割线。
运行上述代码显示效果:
使用LinearLayoutManager的显示效果
recyclerView.setLayoutManager(new LinearLayoutManager(this));
使用StaggeredGridLayoutManager的显示效果
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
使用StaggeredGridLayoutManager显示瀑布流效果需要在adapter中随机设置一下item的高度
adapter代码
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.myViewHolder> { private Context context; private List<String> mDatas; private List<Integer> mHeights; public RecyclerAdapter(Context context, List<String> mDatas) { super(); ... ... mHeights = new ArrayList<Integer>(); for (int i = 0; i < mDatas.size(); i++) { mHeights.add((int) (100 + Math.random() * 300)); }
} @Override public void onBindViewHolder(final myViewHolder holder, int position) { ViewGroup.LayoutParams lp = holder.tv.getLayoutParams(); lp.height = mHeights.get(position); holder.tv.setLayoutParams(lp); ... ... }
其他代码同上面的adapter一样,这里只贴出增加部分,运行效果如下:
上述代码中StaggeredGridLayoutManager构造的第二个参数传一个orientation,如果传入的是StaggeredGridLayoutManager.VERTICAL
代表有多少列;那么传入的如果是StaggeredGridLayoutManager.HORIZONTAL
就代表有多少行。例如改成
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.HORIZONTAL));
相应的Adapter中改成
@Override public void onBindViewHolder(final myViewHolder holder, int position) { ViewGroup.LayoutParams lp = holder.tv.getLayoutParams(); lp.width = mHeights.get(position); holder.tv.setLayoutParams(lp); }
运行效果如下
这里只贴了静态图,其实是可以水平滑动的。
再来说说item的动画效果,RecyclerView 支持item的自定义动画效果。github上也已经出现了好多自定义的效果,这里贴出一个连接吧
https://github.com/wasabeef/recyclerview-animators
当然系统也为我们提供了一个默认的效果
recyclerView.setItemAnimator(new DefaultItemAnimator());
一句代码即可,显示效果如下
adapter中增加两个方法
public void addData(int position) { mDatas.add(position, "New Item"); notifyItemInserted(position); } public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); }
Activity中调用一下
@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_add: adapter.addData(1); break; case R.id.action_delete: adapter.removeData(1); break; } return super.onOptionsItemSelected(item); }
这里需要注意的是RecyclerView 更新数据使用的是 notifyItemInserted(position)
与notifyItemRemoved(position)
这里和listview的notifyDataSetChanged
不同,虽然RecyclerView也提供notifyDataSetChanged
方法,但使用notifyDataSetChanged
是没有任何动画效果的。
由于RecyclerView的扩展行非常强,系统并没有为我们提供setOnItemClickListener方法,这就需要我们自己去定义了,我们可以在adapter中自己去定义item回调接口
public interface OnItemClickLitener { void onItemClick(View view, int position); void onItemLongClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; }
在onBindViewHolder中调用
@Override public void onBindViewHolder(final myViewHolder holder, int position) { ... ...if (mOnItemClickLitener != null) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { int position=holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView,position); return true; } }); } }
Activity中添加以下代码即可
adapter.setOnItemClickLitener(new RecyclerAdapter.OnItemClickLitener() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, position + " click",Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(View view, int position) { Toast.makeText(MainActivity.this, position + " LongClick",Toast.LENGTH_SHORT).show(); } });
运行效果:
献给那些还对RecyclerView还不太熟悉的兄弟们,需要源码请留言。
参考资料
https://github.com/wasabeef/recyclerview-animators
http://blog.csdn.net/lmj623565791/article/details/45059587
http://blog.jobbole.com/74208/