深入解析RecyclerView
- 前言:这段时间一直在总结代码,书写博客!希望自己技术有所提高,在明年的4月份得到好的实习机会!
(一)介绍RecyclerView
RecyclerView到底是什么呢?RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。该控件用于在有限的窗口中展示大量数据集,它被作为ListView和GridView控件的继承者。RecyclerView高度解耦,异常灵活,通过设置不同LayoutManager,ItemDecoration , ItemAnimator实现令人想象不到的效果。首先我们先看一下RecyclerView在我项目中实现的效果图:
【注意】我们可以从中看出RecyclerView可以实现ListView和GridView功能并且成功实现高度定制与解耦!
- 如果想要控制其显示方式:Linear , grid or stagger ,可以通过布局管理器LayoutManager。
- 如果想要控制Item间的间隔以及样式,可以通过ItemDecoration。
- 想要控制Item增删动画,可以通过ItemAnimator。(有默认类)
- 想要控制Item的点击事件,需要自己设置回调监听事件。
我来看一下RecyclerView的一些关键类:
1.Datas: 要显示的数据
2.Adapter:适配器,绑定数据集
3.ViewHolder:根据当前的数据保存视图
4.LayoutManager:布局管理器。决定item如何摆放
5.ItemDecoration:勉强理解为item装饰器,可以美化item
6. ItemAnimator:动画(当item被增加,删除,重新摆放时动画才有效)。
7. Listener: 事件。RecyclerView 本身不提供OnItemClickListener 等事件
首先我们来看一下基本的使用方法:
mAdatper = new MyAdatper(datas);
mRecyclerView.setAdapter(mAdatper);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
【注意】可以看出基本的步骤有:1.实例化自定义的Adapter类,2.设置mAdapter ,3.设置Layout ,4.设置ItemDecoration,5.设置ItemAnimator(非必须,有默认动画属性)。
【注意】使用前需要在Gradle上配置:
compile 'com.android.support:recyclerview-v7:23.0.1'
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List<String> datas = new ArrayList<>();
private MyAdatper mAdatper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDatas();
mRecyclerView = (RecyclerView) this.findViewById(R.id.recyclerView);
mAdatper = new MyAdatper(datas);
mRecyclerView.setAdapter(mAdatper);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdatper.setOnItemClickListener(new MyAdatper.OnItemClickListener() {
@Override
public void onClick(View v, int position, String city) {
Toast.makeText(MainActivity.this,"city:"+city+",position:"+position,Toast.LENGTH_LONG).show();
}
});
}
private void initDatas(){
datas.add("New York");
datas.add("Boston");
datas.add("Washington");
datas.add("San Francisco");
datas.add("California");
datas.add("Chicago");
datas.add("Houston");
datas.add("Phoenix");
datas.add("Philadelphia");
datas.add("Pennsylvania");
datas.add("San Antonio");
datas.add("Austin");
datas.add("Milwaukee");
datas.add("Las Vegas");
datas.add("Oklahoma");
datas.add("Portland");
datas.add("Mexico");
}
}
MyAdapter.java
public class MyAdatper extends RecyclerView.Adapter<MyAdatper.ViewHolder> {
private List<String> mDatas;
private LayoutInflater inflater;
//设置OnItemClickListener接口,实现对Item的监听
private OnItemClickListener listener;
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
//新建Adapter时往里面添加数据List<String>
public MyAdatper(List<String> datas){
mDatas = datas;
}
interface OnItemClickListener{
void onClick(View v,int position,String city);
}
//动态加载Item的布局文件,创建一个ViewHolder
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item,parent,false);
return new ViewHolder(view);
}
//把ViewHolder里面的控件进行数据绑定
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.textView.setText(mDatas.get(position));
}
//得到Item的数量
@Override
public int getItemCount() {
return mDatas.size();
}
public void addData(int position,String city){
mDatas.add(position,city);
//通知添加Item
notifyItemInserted(position);
}
public void removeData(int position){
mDatas.remove(position);
//通知取出Item
notifyItemRemoved(position);
}
//对布局文件中的控件进行绑定,并在其中对布局文件或者Item建立监听机制
class ViewHolder extends RecyclerView.ViewHolder{
private TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener !=null){
listener.onClick(v,getLayoutPosition(),mDatas.get(getLayoutPosition()));
}
}
});
}
}
}
- activity_main.xml中的布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
- item.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_item_bg"
android:gravity="center"
android:padding="20dp"
>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#fff"
android:textSize="20dp"
android:padding="20dp"
android:text="1" />
</LinearLayout>
- 效果图如下:
【注意】当我们需要对其设置decoration,即各个Item之间的分割线时,需要添加:mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
注意,DividerItemDecoration是RecyclerView.ItemDecoration的实现类,该类很好的实现了RecyclerView添加分割线(当使用LayoutManager为LinearLayoutManager时)。 如果读者需要该类,可以在评论里留下邮箱。
LayoutManager
RecyclerView.LayoutManager吧,这是一个抽象类,好在系统提供了3个实现类:
LinearLayoutManager 现行管理器,支持横向、纵向。 GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器
上面我们已经初步体验了下LinearLayoutManager,接下来看GridLayoutManager。
//mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
对此需要编写新的DividerGridItemDecoration类,需要的读者在评论里留下邮箱。
ItemAnimator
ItemAnimator也是一个抽象类,系统为我们提供了一种默认的实现类,当Item添加和移除时,添加动画效果很简单:
// 设置item动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
在上述的adapter中添加俩个方法:
public void addData(int position,String city){
mDatas.add(position,city);
//通知添加Item
notifyItemInserted(position);
}
public void removeData(int position){
mDatas.remove(position);
//通知取出Item
notifyItemRemoved(position);
}
- 在MainActivity中点击MenuItem触发:
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.id_action_add:
mAdatper.addData(0,"new Citiy");
break;
case R.id.id_action_delete:
mAdatper.removeData(1);
break;
case R.id.id_action_gridview:
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4));
break;
case R.id.id_action_listview:
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
break;
case R.id.id_action_horizontalGridView:
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
StaggeredGridLayoutManager.HORIZONTAL));
break;
}
return true;
}
Onclick方法
- 系统没有实现对Item的监听,所以需要我们自己定义回调:
//设置OnItemClickListener接口,实现对Item的监听
private OnItemClickListener listener;
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
interface OnItemClickListener{
void onClick(View v,int position,String city);
}
- 在ViewHolder中对Item点击触发
textView = (TextView) itemView.findViewById(R.id.text);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener !=null){
listener.onClick(v,getLayoutPosition(),mDatas.get(getLayoutPosition()));
}
}
});