前言
RecyclerView标准化了ViewHolder,可以轻松实现ListView实现不了的样式和功能,通过布局管理器LayoutManager可控制Item的布局方式,通过设置Item操作动画自定义Item添加和删除的动画,通过设置Item之间的间隔样式,自定义间隔。
那么,综合上面的特点,我们可以得到,RecyclerView的四大部分
- 适配器
- LayoutManager控制布局样式
- 自定义Item间隔线
- 添加动画
那我们来分别学习一下。
添加依赖:
implementation 'androidx.recyclerview:recyclerview:1.0.0'
适配器的使用
在RecyclerView中,适配器的一些基本的封装都已经被做好了,我们定义一个类去继承RecyclerView.Adapter<T extends RecyclerView.ViewHolder>,然后去实现相应的方法即可。
继承RecyclerView.Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
}
}
我们来分别了解下其中的几个方法:
- 自己的ViewHolder的ViewHolder(@NonNull View itemView)方法:这个方法就是用来存储我们的item的
- onCreateViewHolder:顾名思义,使用来创建实例化我们的viewholder对象的,我们可以在里面这么操作
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
这样子,我们就将我们的item对象传到viewholder里面了。
- 初始化viewholder:我们从onCreateViewHolder中得到viewHolder对象后,对item里面的组件进行初始化,那我们的viewholder修改之后为
class ViewHolder extends RecyclerView.ViewHolder {
TextView item_tv_explain;
TextView item_tv_key;
TextView item_tv_value;
public ViewHolder(@NonNull View itemView) {
super(itemView);
item_tv_explain = itemView.findViewById(R.id.item_tv_explain);
item_tv_key = itemView.findViewById(R.id.item_tv_key);
item_tv_value = itemView.findViewById(R.id.item_tv_value);
}
}
- getItemCount方法:这个方法是用来得到我们的list数量大小的,所以,我们需要在Adapter的构造方法里面传入我们需要数据源,然后在这个方法里面返回大小,如:
ArrayList<RequestEntity> list_request; //总的请求信息
public MyAdapter(ArrayList<RequestEntity> list_request) {
this.list_request = list_request;
}
public int getItemCount() {
return list_request == null ? 0 : list_request.size();
}
- onBindViewHolder:这个方法就是用来绑定item的view和数据的,如
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.item_tv_explain.setText(list_request.get(position).explain);
holder.item_tv_key.setText(list_request.get(position).key);
holder.item_tv_value.setText(list_request.get(position).value);
}
这样子,我们就完成了适配器的编写
附加:layout/item_request_info.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:weightSum="10"
android:background="#FFFFFF"
android:layout_height="40dp">
<TextView
android:layout_width="0dp"
android:layout_weight="2"
android:gravity="center"
android:id="@+id/item_tv_explain"
android:layout_height="match_parent" />
<TextView
android:layout_width="0dp"
android:layout_weight="4"
android:gravity="center"
android:id="@+id/item_tv_key"
android:layout_height="match_parent" />
<TextView
android:layout_width="0dp"
android:layout_weight="4"
android:gravity="center"
android:id="@+id/item_tv_value"
android:layout_height="match_parent" />
</LinearLayout>
打造万能适配器
万能ViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
View itemView;
private SparseArray<View> mViews;
public ViewHolder(@NonNull View itemView) {
super(itemView);
this.itemView = itemView;
this.mViews = new SparseArray<>();
}
public static ViewHolder get(ViewGroup parent, int viewType) {
View v;
if(viewType == 1) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info1, parent, false);
} else {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info2, parent, false);
}
return new ViewHolder(v);
}
public ViewHolder setTextViewValue(int viewId,String text)
{
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
private <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null)
{
view = itemView.findViewById(viewId);
mViews.put(viewId,view);
}
return (T) view;
}
}
万能适配器
public abstract class NetRvAdapter1<T> extends RecyclerView.Adapter<ViewHolder> {
ArrayList<T> list_request; //总的请求信息
public NetRvAdapter1(ArrayList<T> list_request) {
this.list_request = list_request;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return ViewHolder.get(parent,viewType);
}
@Override
public int getItemViewType(int position) {
// 瀑布流样式外部设置spanCount为2,在这列设置两个不同的item type,以区分不同的布局
return position % 2;
}
public abstract void convert(ViewHolder holder,T t);
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
convert(holder,list_request.get(position));
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(onItemClickListener != null) {
int pos = holder.getLayoutPosition();
onItemClickListener.onItemLongClick(holder.itemView, pos);
}
//表示此事件已经消费,不会触发单击事件
return true;
}
});
}
@Override
public int getItemCount() {
return list_request == null ? 0 : list_request.size();
}
public void addNewItem(int index,T t) {
if(list_request == null) {
list_request = new ArrayList<>();
}
list_request.add(index, t);
notifyItemInserted(index);
}
public void deleteItem(int index) {
if(list_request == null || list_request.isEmpty()) {
return;
}
list_request.remove(index);
notifyItemRemoved(index);
}
/**
* 事件回调监听
*/
private NetRvAdapter1.OnItemClickListener onItemClickListener;
/**
* 设置回调监听
*
* @param listener
*/
public void setOnItemClickListener(NetRvAdapter1.OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
}
使用
public class RealAdapter extends NetRvAdapter1<RequestEntity> {
public RealAdapter(ArrayList<RequestEntity> list_request) {
super(list_request);
}
@Override
public void convert(ViewHolder holder, RequestEntity entity) {
holder
.setTextViewValue(R.id.item_tv_explain,entity.explain)
.setTextViewValue(R.id.item_tv_key,entity.key)
.setTextViewValue(R.id.item_tv_value,entity.value);
}
}
adapter = new RealAdapter(list_request);
rv_request_details.setAdapter(adapter);
选择LayoutManager控制布局样式
RecyclerView提供了三种布局样式
- LinerLayoutManager 以垂直或者水平列表方式展示Item
- GridLayoutManager 以网格方式展示Item
- StaggeredGridLayoutManager 以瀑布流方式展示Item
我们首先来学习下LinerLayoutManager来实现垂直和水平方向展示item
LinerLayoutManager
垂直方向展示item
我们继续使用上面的item布局文件,然后在MainActivity中编写代码,如:
private void initView() {
adapter = new NetRvAdapter(list_request);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置布局管理器
rv_request_details.setLayoutManager(layoutManager);
//设置为垂直布局,这也是默认的
layoutManager.setOrientation(OrientationHelper.VERTICAL);
//设置Adapter
rv_request_details.setAdapter(adapter);
}
截图:
screen.png
水平方向展示item
我们修改item布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="60dp"
android:weightSum="10"
android:background="#FFFFFF"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_weight="2"
android:gravity="center"
android:id="@+id/item_tv_explain"
android:layout_height="0dp" />
<TextView
android:layout_width="match_parent"
android:layout_weight="4"
android:gravity="center"
android:id="@+id/item_tv_key"
android:layout_height="0dp" />
<TextView
android:layout_width="match_parent"
android:layout_weight="4"
android:gravity="center"
android:id="@+id/item_tv_value"
android:layout_height="0dp" />
</LinearLayout>
修改MainActivity中的代码,如:
private void initView() {
adapter = new NetRvAdapter(list_request);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置布局管理器
rv_request_details.setLayoutManager(layoutManager);
//设置为垂直布局,这也是默认的
layoutManager.setOrientation(OrientationHelper.HORIZONTAL); //这里
//设置Adapter
rv_request_details.setAdapter(adapter);
}
截图:
screen.png
GridLayoutManager 以网格方式展示Item
构造函数以及参数含义:
- GridLayoutManager(Context context, int spanCount)
- spanCount,每列或者每行的item个数,设置为1,就是列表样式
该构造函数默认是竖直方向的网格样式
- spanCount,每列或者每行的item个数,设置为1,就是列表样式
- GridLayoutManager(Context context, int spanCount, int orientation,boolean reverseLayout)
- spanCount,每列或者每行的item个数,设置为1,就是列表样式
网格样式的方向,水平(OrientationHelper.HORIZONTAL)或者竖直(OrientationHelper.VERTICAL) - reverseLayout,是否逆向,true:布局逆向展示,false:布局正向显示
- spanCount,每列或者每行的item个数,设置为1,就是列表样式
使用
修改布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="#FFFFFF"
android:gravity="center"
android:layout_height="100dp">
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_explain"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_key"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_value"
android:layout_height="wrap_content" />
</LinearLayout>
在MainActivity中设置
// 竖直方向的网格样式,每行四个Item
GridLayoutManager mLayoutManager = new GridLayoutManager(this, 4, OrientationHelper.VERTICAL, false);
rv_request_details.setLayoutManager(mLayoutManager);
截图:
screen.png
StaggeredGridLayoutManager 以瀑布流方式展示Item
我们新增两个布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="#03B8FF"
android:gravity="center"
android:layout_height="100dp">
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_explain"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_key"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_value"
android:layout_height="wrap_content" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="#FFA303"
android:gravity="center"
android:layout_height="130dp">
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_explain"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_key"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:gravity="center"
android:id="@+id/item_tv_value"
android:layout_height="wrap_content" />
</LinearLayout>
修改Adapter文件:
ArrayList<RequestEntity> list_request; //总的请求信息
public MyAdapter(ArrayList<RequestEntity> list_request) {
this.list_request = list_request;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v;
if(viewType == 1) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info1, parent, false);
} else {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info2, parent, false);
}
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public int getItemViewType(int position) {
// 瀑布流样式外部设置spanCount为2,在这列设置两个不同的item type,以区分不同的布局
return position % 2;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.item_tv_explain.setText(list_request.get(position).explain);
holder.item_tv_key.setText(list_request.get(position).key);
holder.item_tv_value.setText(list_request.get(position).value);
}
@Override
public int getItemCount() {
return list_request == null ? 0 : list_request.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView item_tv_explain;
TextView item_tv_key;
TextView item_tv_value;
public ViewHolder(@NonNull View itemView) {
super(itemView);
item_tv_explain = itemView.findViewById(R.id.item_tv_explain);
item_tv_key = itemView.findViewById(R.id.item_tv_key);
item_tv_value = itemView.findViewById(R.id.item_tv_value);
}
}
在MainActivity中设置
// 初始化布局管理器
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
// 设置布局管理器
rv_request_details.setLayoutManager(mLayoutManager);
截图:
screen.png
未完待续...
网友评论