RecyclerView(一)主要介绍了RecyclerView基础的使用方式,用于列表展示大量数据,介绍了一些方法和类的关系。列表中的数据通过一个LIst数据结构保存,通过adapter进行绑定和渲染,在使用RecyclerView时,不可避免的会遇到展示列表信息的变更,即List内容的更改,RecyclerView不会自动的展示更改,需要进行刷新操作。
每个列表都对应了一个List的数据结构,对于类表的增删改都是通过对List进行的,本文在上一篇文章的基础上增加一个按钮,点击按钮后,增加adapter中list的数据:
btn = (Button)findViewById(R.id.mbtn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList data = new ArrayList<>();
for(int i=10;i<20;i++){
data.add(i);
}
adapter.addData(data);
}
});
adapter中addData方法,直接在原来的List后添加新的数据,如下:
public void addData(ArrayList data){
this.data.addAll(data);
}
运行的效果为:
可以发现按钮点击后,只改变list数据,列表并没有自动更新。上篇文章中设置了自定义间隔,点击按钮前,5号item是最后一个,所以右边的间隔设置为50,点击按钮后,由于item5不是list数据中的最后一位,渲染时间隔就变为了12.
要使列表随着list的更新变化,就要进行刷新操作,说白了就是要告诉RecyclerView,数据发生了变化。RecyclerVIew的刷新我把他分为三个等级:全部刷新、局部刷新、控件刷新。
//更新指定位置
public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}
/**
* 更新一部分位置
* 从positionStart开始itemCount个数据
*/
public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}
public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
}
当payload为NULL时,即是局部刷新,需要重写onBindViewHolder(ViewHolder holder, int position, List
@Override
public void onBindViewHolder(ViewHolder holder, int position, List
列表除了展示数据之外,还需要对点击事件进行响应,ListView中可以直接通过setItemClickListener来设置列表点击的监听,而RecyclerView没有给我们提供这样的接口,所以对于RecyclerView列表的点击需要我们自己创建,目前主流的方法有两种种
虽然RecyclerView没有提供item的点击事件接口,但是由于每个item的视图是由我们自己定义的,可以通过对视图控件的点击事件进行监听,从而实现item的点击监听。
列表再滚动的时候,会通过onbind()方法得到要显示的视图,可以再此方法中对View进行点击监听。这里最好建一个全局的listener,通过view.getID或getTag等方式判断点击的是哪个item,而不是给每个view 都创建一个监听器,这样在列表滑动时可以避免大量的对象创建和销毁。保证滑动的性能。
@NonNull
@Override
public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item_view,parent,false);
MyAdapter.ViewHolder viewHolder = new MyAdapter.ViewHolder(view);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
return viewHolder;
}
在adapter中实现View点击后的具体逻辑即可,
@Override
public void onClick(View v) {
int position = mRecyclerView.getChildAdapterPosition(v);
Toast.makeText(context,"第"+position+"个被点击",Toast.LENGTH_SHORT).show();
}
@Override
public boolean onLongClick(View v) {
int position = mRecyclerView.getChildAdapterPosition(v);
...//添加长按处理的逻辑
return true;
}
但是使用ListView的时候,我们的点击事件是通过adapter.setOnItemClickListener设置的,直接在Activity中就可以设置,比较方便,封装更好,所以我们也要想办法将接口暴露出来,方便调用。
首先创建一个接口
interface ItemClickListener{
void onclick(int position);
void onLongClick(int position);
}
在adapter中View的点击事件处理中,不写具体处理逻辑,只执行接口的方法,具体逻辑由实现了接口方法的类去实现
private ItemClickListener itemClickListener;
@Override
public boolean onLongClick(View v) {
int position = mRecyclerView.getChildAdapterPosition(v);
itemClickListener.onLongClick(position);
}
public void onClick(View v) {
int position = mRecyclerView.getChildAdapterPosition(v);
itemClickListener.onclick(position);
}
然后将实现了接口的类传进来,就可以实现调用。例如我们在Activity中实现接口:
mAdapter.setItemClickListener(new MyAdapter.ItemClickListener() {
@Override
public void onclick(int position) {
Toast.makeText(MainActivity.this,"第"+position+"位置点击",Toast.LENGTH_SHORT).show();
}
@Override
public void onLongClick(int position) {
//长按事件
}
});
addOnItemTouchListener是RecyclerVIew中的一个内部接口,可以对RecyclView中的触摸事件进行拦截,接口方法如下:
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
在onInterceptTouchEvent中可以获取当前触摸位置对应的子item view,使用GestureDetector判断点击状态,决定是否要把事件拦截,在拦截的时候同时添加一个回调方法处理。实现起来比较麻烦,后续再写。