0. 引言
ListView在一些简单场合应用是绰绰有余的,但是在复杂场合例如需要实时更新或者实现瀑布流等炫酷效果时就需要做许多工作来提高运行效率,这时候性能就显得很一般,同时扩展性也不够强,只能横向滚动等问题无法解决。
为此,Android提供了一种更强大的滚动控件——RecyclerView。它是一个增强版ListView,可以完全替代ListView并且优化了不足,增加了许多可扩展功能。从整体上来看,RecyclerView具有高度解耦、异常的灵活性、更高的效率。通过设置他的布局管理器,动画效果等可以实现丰富多彩的样式效果,所以RecyclerView也是官方推荐使用的控件,本文就简单总结记录下RecyclerView的使用方法。
1. RecyclerView依赖的添加
想要使用RecyclerView,我们首先不要忘记在项目的build.gradle
中添加相应的依赖库才行,一般的添加方法是在Project Structure下点击+号之后添加依赖如图所示:
添加后build.gradle
是这样的,注意红圈部分的版本号应该保持一致
2. RecyclerView的基本布局
首先要用RecyclerView实现前文的效果,需要一个水果类和相应的Adapter,以及对应的item布局,水果类和布局就用之前的,这里就简单贴一下代码不作赘述了。
activity_main.xml
部分代码
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/recyclerView"
>
item.xml
部分代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/list_item">
<ImageView
android:id="@+id/image"
android:layout_width="40dp"
android:layout_height="40dp"
/>
<TextView
android:id="@+id/name"
android:layout_width="50dp"
android:layout_height="40dp" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
3 .RecyclerView的Adapter配置
接下来要为RecyclerView搞一个适配器,这里我认为就是RecyclerView跟ListView最大不同的地方了,RecyclerView的Adapter可以继承RecyclerView.Adapter同时最大的改进就是对ViewHolder进行了封装定义,只需要自定义一个ViewHolder
继承RecyclerView.ViewHolder
就行了,这就非常方便同时又能提高运行效率。
首先新建一个RecyclerAdapter类,泛型这里指定为RecyclerAdapter.ViewHolder
即可,其中ViewHolder是我们自定义的继承自RecyclerView.ViewHolder的类.
Adapter配置代码如下:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder
{
TextView fruitname;
TextView fruitctx;
ImageView fruitImg;
View fruitview;
public ViewHolder(View itemView) {
super(itemView);
fruitview=itemView; //保存整个itemView
fruitname = (TextView) itemView.findViewById(R.id.name);
fruitctx= (TextView) itemView.findViewById(R.id.content);
fruitImg = (ImageView) itemView.findViewById(R.id.image);
}
}
public RecyclerAdapter(List<Fruit> fruitList){
mFruitList=fruitList; //要传入的总集合
}
public void removeData(int pos)
{
mFruitList.remove(pos);
notifyItemRemoved(pos);
notifyItemRangeChanged(pos,mFruitList.size());//通知数据与界面重新绑定
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem,parent,false);
final ViewHolder viewHolder =new ViewHolder(view);//实例化viewholder
//分别注册整个的监听器
viewHolder.fruitview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//第一步都是先拿位置
int position= viewHolder.getAdapterPosition();
//第二步再实例化这个对象
Fruit fruit =mFruitList.get(position);
Toast.makeText(view.getContext(),fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
viewHolder.fruitview.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
final int position =viewHolder.getAdapterPosition();
new AlertDialog.Builder(view.getContext())
.setTitle("确定删除吗?").setNegativeButton("cancel",null)
.setPositiveButton("yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
removeData(position);
}
}).show();
return false;
}
});
//再单独注册图片的监听器
viewHolder.fruitImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int pos =viewHolder.getLayoutPosition();
Fruit fruit=mFruitList.get(pos);
Toast.makeText(view.getContext(),"点的是图片",Toast.LENGTH_SHORT).show();
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit =mFruitList.get(position);
holder.fruitname.setText(fruit.getName());
holder.fruitctx.setText(fruit.getContent());
holder.fruitImg.setImageResource(fruit.getImage());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
}
暂且先不管里面的点击监听检测部分,首先创建这个Adapter的时候AS会自动生成onCreateViewHolder、onBindViewHolder、getItemCount 三个方法所以不用担心记不住,这三个方法是需要重写的,他们的作用分别是:
onCreateViewHolde
r:创建ViewHolder实例,并且用LayoutInflater传入item布局,传入以后再交给ViewHolder来实例化,最后返回ViewHolder。onBindViewHolder
:用来将界面与数据进行绑定,同样记住是利用ViewHolder来操作,先临时创建一个水果类,然后根据位置实例化拿到具体属性,在通过创建好的holder来具体给部局界面设置相应的参数属性。getItemCount
:这个就比较简单了,就是返回一下集合的长度大小。
搞清楚了这三个函数的作用和功能,RecyclerView的Adapter就不难理解了。
4. RecyclerView的点击事件
不同于ListView,RecyclerView没有提供直接注册监听器的方法,需要我们给item中具体的View去注册点击事件,虽然看起来比ListView复杂,但是仔细想想这样一来就可以具体给item中每个View分配监听,这样就可以分开来处理点击事件了,是不是更加灵活了呢。
具体到代码里面就是,先在ViewHolder里创建整体View(图中1),然后在ViewHolder构造函数里面保存下整个itemView(图中2),代码如下
static class ViewHolder extends RecyclerView.ViewHolder
{
TextView fruitname;
TextView fruitctx;
ImageView fruitImg;
View fruitview; -----1
public ViewHolder(View itemView) {
super(itemView);
fruitview=itemView; //保存整个itemView -----2
fruitname = (TextView) itemView.findViewById(R.id.name);
fruitctx= (TextView) itemView.findViewById(R.id.content);
fruitImg = (ImageView) itemView.findViewById(R.id.image);
}
}
之后就很简单啦,分别通过holder来给你想要的部分注册监听器就OK了
//分别注册整个的监听器
viewHolder.fruitview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//第一步都是先拿位置
int position= viewHolder.getAdapterPosition();
//第二步再实例化这个对象
Fruit fruit =mFruitList.get(position);
Toast.makeText(view.getContext(),fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
//再单独注册图片的监听器
viewHolder.fruitImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int pos =viewHolder.getLayoutPosition();
Fruit fruit=mFruitList.get(pos);
Toast.makeText(view.getContext(),"点的是图片",Toast.LENGTH_SHORT).show();
}
});
当点击图片时
当点击文字时
5. RecyclerView 添加/删除Item
首先可以在main_Activity
初始化时使用下面的语句设置增删的动画:
//设置item增加和删除的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
然后回到刚才的Adapter中,可以自定义个删除方法,如下:
public void removeData(int pos)
{
mFruitList.remove(pos); //1.去除这个点击位置处对应集合中元素实例
notifyItemRemoved(pos); //2.调用动画方法删除这个item
notifyItemRangeChanged(pos,mFruitList.size()); //3.通知数据与界面重新绑定
}
注意:由于动画播放前后,onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)
中的position形参其实是没有改变的。但实际上由于添加/删除Item的影响,被点击的Item的position值应该添加1或减少1。所以RecyclerView这些动画效果方法在本质上并不能等价于ListView的notifydatasetchanged方法。故正确地添加/删除Item的步骤应该为先在集合中永久去除这个点击位置的实例,再调用动画方法,最后通知Adapter重新绑定数据与界面,就可以完成真正的增删更新界面啦。
之后就是注册长按监听器,用对话框来确认是否确定删除,确定后有删除动画,这里还要注意
notifyItemRangeChanged(pos,mFruitList.size())
两个参数分别是删除位置和总长度,这个方法的作用就是对删除位置和后面所有item进行更新界面,比较高效,所有notify开头的方法中,仅仅只有以下三个方法带有“Changed”且具有重新绑定数据与界面的功能,它们分别是:
notifyDataSetChanged();//通知重新绑定所有数据与界面
notifyItemChanged(int);//通知重新绑定某一个Item的数据与界面
notifyItemRangeChanged(int, int);//通知重新绑定某一范围内的的数据与界面
之后只需要调用删除方法就行啦,增加的方法相同在此不再赘述啦~
});
viewHolder.fruitview.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
final int position =viewHolder.getAdapterPosition();
new AlertDialog.Builder(view.getContext())
.setTitle("确定删除吗?").setNegativeButton("cancel",null)
.setPositiveButton("yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
removeData(position);
}
}).show();
return false;
}
});
询问是否删除
删除梨子和香蕉后:
6. RecyclerView的初始化
适配器完全准备好以后,就可以开始使用了,这部分主要在MainActivity中进行,代码如下:
public class MainActivity extends AppCompatActivity {
List<Fruit> fruit =new ArrayList<>();
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initfruit();
recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
RecyclerAdapter recyclerAdapter =new RecyclerAdapter(fruit);
//设置布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置item增加和删除的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(recyclerAdapter);
}
private void initfruit() {
for(int i=0;i<2;i++)
{
Fruit apple =new Fruit("apple","This is a apple",R.drawable.apple);
fruit.add(apple);
Fruit pear =new Fruit("pear","This is a pear ",R.drawable.pear);
fruit.add(pear);
Fruit banana=new Fruit("banana","This is a banana",R.drawable.bannana);
fruit.add(banana);
}
}
}
首先创建了一个水果类集合,并对其进行了初始化。之后实例化RecyclerView,并且创建了一个我们自己写的RecyclerAdapter。这里要注意,RecyclerView必须要设置布局管理器,用来设置item的排列样式,可以是垂直或者水平排列,这里一般用new LinearLayoutManager(this)也就是线性排列就行了,默认垂直。如果要设置成水平可以写成下面这样然后再传给 RecyclerAdapter
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
之后使用
recyclerView.setItemAnimator(new DefaultItemAnimator())
来给item的增删添加动画效果
recyclerView.setAdapter(recyclerAdapter);
最后挂上适配器就OK啦~
总结
到此RecyclerView的简单应用就酱紫啦^_^,参考了一些郭神和刘神的代码还有官方文档,当然还有分界线,瀑布流等等更复杂的应用有待继续深入学习,欢迎大佬提出建议,与大家共勉~♪(^∀^●)ノ