1, 概述
RecyclerView已经出现有两三年了,虽然没有listview使用广泛,但是RecyclerView更加灵活,实现一些功能时比listview更简单。本文主要介绍RecyclerView的一些基本功能,具体的实现。
Adapter:为RecyclerView提供数据,处理每个item的显示。
LayoutManager:管理RecyclerView的显示结构。
ItemDecoration:添加每个item的装饰。
ItemAnimator:负责item添加/移除/重排时的动画效果。
其中,前2项是必须实现的,后面2项是可选的,并且都有对应的设置方法,
setAdapter/setLayoutManager/addItemDecoration/setItemAnimator。
RecyclerView布局文件定义如下,
<android.support.v7.widget.RecyclerView
android:id="@+id/staggered_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
2 Adapter
2.1, Adapter
实现RecyclerView.Adapter, RecyclerView中强制使用ViewHolder,
必须实现3个方法,
onCreateViewHolder: 自定义创建item的View
onBindViewHolder: 设置item所显示的数据
getItemCount:获取item的数量
public class Readapter extends RecyclerView.Adapter<MyViewHolder>{
private List<String> mstring; // 保存所显示的字符串
private List<Integer> mheights; // 保存每个item的高度
Readapter(List<String> datastring,List<Integer> dataheights){
mstring = datastring;
mheights = dataheights;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
parent.getContext()).inflate(R.layout.item_recycle_view, parent,false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position){
holder.getlable.setText(mstring.get(position)); // 设置item所显示的字符串
if(!mheights.isEmpty()){ // 设置item的高度
ViewGroup.LayoutParams lp = holder.getlable.getLayoutParams();
lp.height = mheights.get(position);
}
}
@Override
public int getItemCount(){
return mstring.size();
}
}
2.2 ViewHolder
实现RecyclerView.ViewHolder,自定义view
public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView tv;
public MyViewHolder(View view) {
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
public TextView getlable(){
return tv;
}
}
这样,有了mstring之后,就可以显示了。
在activity中,完成相关设置
mRecyclerView = (RecyclerView) findViewById(R.id.staggered_recycler); // 获取mRecyclerView
mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); // 设置LinearLayoutManager
Readapter myadpter = new Readapter(datastring, dataheights); // 构造Readapter
mRecyclerView.setAdapter(myadpter); // 设置adpter
这样,类似于listview的界面就显示了。
几乎和listview来显示item差不多,还稍微有点麻烦
3LayoutManager
RecyclerView.LayoutManager是一个抽象类,如何去实现呢? 系统提供了3个实现类:
LinearLayoutManager 线性布局,支持横向、纵向。
GridLayoutManager 网格布局
StaggeredGridLayoutManager 流式布局
3.1 LinearLayoutManager
LinearLayoutManager设置方法如下,一般在activity中,
LinearLayoutManager mLinearLayoutManager;
mLinearLayoutManager = new LinearLayoutManager(this); // 创建线性布局
mLinearLayoutManager.setOrientation(OrientationHelper.VERTICAL); // 垂直
// mLinearLayoutManager.setOrientation(OrientationHelper.HORIZONTAL);
mRecyclerView.setLayoutManager(mLinearLayoutManager); // 设置LinearLayoutManager
另外,在OrientationHelper类中,
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
3.2 GridLayoutManager
mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));// 表示有4列
3.3 StaggeredGridLayoutManager
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); // StaggeredGridLayoutManager.HORIZONTAL
// 2个参数,如果第2个参数为VERTICAL,那就表示分为4列
如果2个参数为HORIZONTAL,那就表示分为4行
如果要实现每个item的高度不一样,向下面这样的,在activity中,
如果用liseview是很难实现的,但是用StaggeredGridLayoutManager就很容易,
首先为每个item随机生成不同的高度,
dataheights = new ArrayList<>();
Int height;
For(int i=0;i< datastring.size();i++){
height = (int) 100+Math.random*300;
Dataheights.add(height);
}
然后,在adapter的onBindViewHolder方法为每一个item设置高度,
Readapter中的onBindViewHolder方法如下,
@Override
public void onBindViewHolder(MyViewHolder holder, int position){
holder.getlable.setText(mstring.get(position)); // 设置item所显示的字符串
if(!mheights.isEmpty()){ // 设置item的高度
ViewGroup.LayoutParams lp = holder.getlable.getLayoutParams();
lp.height = mheights.get(position);
}
}
4 添加删除item
添加item,
datastring.add(position, "Insert One");
myadpter.notifyItemInserted(position);
删除
datastring.remove(position);
myadpter. notifyItemRemoved(position);
注意,更新item不是用adapter.notifyDataSetChanged而是
notifyItemInserted(position)与notifyItemRemoved(position)
添加单击事件
RecyclerView并没有提供ClickListener和LongClickListener,所以需要的话,需要添加,一般的方法是通过adapter中提供回调。
在adapter添加接口,
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(MyViewHolder holder, int position){
holder.getlable.setText(mstring.get(position)); // 设置item所显示的字符串
if(!mheights.isEmpty()){ // 设置item的高度
ViewGroup.LayoutParams lp = holder.getlable.getLayoutParams();
lp.height = mheights.get(position);
}
if (mOnItemClickLitener != null) {
int pos;
holder.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);
//回调方法,,将view控件和索引传回,索引必须是布局在父布局中的索引,否则索引错乱最终报错
}
});
holder.setOnLongClickListener(new OnLongClickListener(){
@Override
public boolean onLongClick(View v) {
pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
}
Activity中去设置监听:
mAdapter.setOnItemClickLitener(new OnItemClickLitener(){
@Override
public void onItemClick(View view, int position) {
•••
}
@Override
public void onItemLongClick(View view, int position) {
•••
}
});
5,刷新
同样的, 在界面刷新时,会调用RecyclerView的onLayout方法,调用流程图如下,
getItemCount/onCreateViewHolder/onBindViewHolder这三个方法都是Adapter的抽象方法,因此需要子类实现。