RecyclerView使用
1. 基础使用
RecyclerView需要自己继承RecyclerView.Adapter以及RecyclerView.ViewHolder。
-
实现ViewHolder,作用就是初始Item中要用的子控件,其作为Adapter的内部类即可。
static class MyViewHolder extends RecyclerView.ViewHolder { TextView titleTv; TextView contentTv; TextView desTv; public MyViewHolder(View itemView) { super(itemView); titleTv=itemView.findViewById(R.id.tv_title); contentTv=itemView.findViewById(R.id.tv_content); desTv=itemView.findViewById(R.id.tv_des); } } 复制代码
-
实现Adapter,这里有三个重要的方法,onCreateViewHolder创建ViewHolder实例,onBindViewHolder将数据绑定到ViewHolder实例中,getItemCount获取列表的数量。
public class VerticalRecyclerViewAdapter extends RecyclerView.Adapter<VerticalRecyclerViewAdapter.MyViewHolder> { private ArrayList<Book> data; private Context mContext; public void setData(ArrayList<Book> data) { this.data = data; notifyDataSetChanged(); } public VerticalRecyclerViewAdapter(Context context) { mContext = context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view= LayoutInflater.from(mContext).inflate(R.layout.view_item1,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.title.setText(data.get(position).getName()); } @Override public int getItemCount() { return data == null ? 0 : data.size(); } static class MyViewHolder extends RecyclerView.ViewHolder { public TextView title; public TextView content; public TextView des; public MyViewHolder(View itemView) { super(itemView); title = itemView.findViewById(R.id.tv_title); content = itemView.findViewById(R.id.tv_content); des = itemView.findViewById(R.id.tv_des); } } } 复制代码
-
在Activity或者Fragment中配置控件,可以设置item横向布局、竖向布局、网格布局
// 配置布局方式 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(linearLayoutManager); // 初始化adapter mAdapter = new VerticalRecyclerViewAdapter(this); mAdapter.setData(list); // 为RecyclerView设置Adapter mRecyclerView.setAdapter(mAdapter); // 设置网格布局 GridLayoutManager gridLayoutManager=new GridLayoutManager(this,3); // 重新设置列数 gridLayoutManager.setSpanCount(2); 复制代码
2. 进阶使用
2.1 点击事件
要监听RecyclerView中Item的点击事件一般有两种实现方式,第一种是在Adapter中进行点击事件的处理,第二种是在外部实现点击事件处理。
// 定义接口
public interface OnItemClickListener {
void onItemClick(View view, Book book);
}
// 监听器的注入,可使用构造时注入,也可以使用setter注入。
private Context mContext;
private OnItemClickListener mOnItemClickListener;
public ClickRecyclerViewAdapter(Context context, OnItemClickListener onItemClickListener) {
mContext = context;
mOnItemClickListener = onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
// 数据绑定及具体控件的事件监听
public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {
holder.titleBtn.setText("按钮:" + (position + 1));
holder.titleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "在adapter中实现点击处理逻辑", Toast.LENGTH_SHORT).show();
}
});
holder.desTv.setText(data.get(position).toString());
holder.desTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v, data.get(position));
}
});
}
// 在初始化Adapter时可以注入事件处理逻辑
ClickRecyclerViewAdapter adapter=new ClickRecyclerViewAdapter(this, new ClickRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, Book book) {
Snackbar.make(view,"外部注入的点击逻辑:"+view.getId(),Snackbar.LENGTH_SHORT).setAction("Action",null).show();
}
});
复制代码
2.2 分组
分组的实现有多种方式,最简单的是header和body写在一个布局中,绑定数据时进行比较,若和上一个位置的数据是同一组的,即隐藏本Item的header。 注意:这要求传入的数据就是分组好的。主要实现如下: Item布局如下
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".group.Item5Activity">
<TextView
android:id="@+id/tv_group_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/blueviolet"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_group_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:background="@color/beige"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_group_title" />
</android.support.constraint.ConstraintLayout>
复制代码
按照数据分组的逻辑如下:
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.titleTv.setText(data.get(position).getName());
holder.contentTv.setText(data.get(position).getContent());
// title 就是header
if (position == 0) {
holder.titleTv.setVisibility(View.VISIBLE);
} else {
if (data.get(position).getName().equals(data.get(position - 1).getName())) {
holder.titleTv.setVisibility(View.GONE);
} else {
holder.titleTv.setVisibility(View.VISIBLE);
}
}
}
复制代码
2.3 悬浮吸顶
悬浮吸顶的实现同样需要用到分组,具体思路是在RecyclerView最上方固定一个header布局,当列表中的header滚动到此处时,将固定的header向上滑动。当header滑出之后更换为下一个header
- RecyclerView布局,将RecyclerView和header放在一起。
<android.support.constraint.ConstraintLayout 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=".sticky.Item7Activity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_item7_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
<include layout="@layout/view_item7_sticky_header_item" />
</android.support.constraint.ConstraintLayout>
复制代码
- Item布局文件,和分组的实现一样。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/view_item7_sticky_header_item" />
<TextView
android:id="@+id/tv_sticky_body"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
复制代码
- 分组显示并为Item设置标记位
public static final int FIRST_STICKY_TAG = 1;// 是否是第一个元素
public static final int HAS_STICKY_TAG = 2;// 该Item是带有Header
public static final int NONE_STICKY_TAG = 3;// 该Item没有Header
/**
* 分组显示的核心思路就是,header和body 分开显示,header的显示取决于当前item的头部是否和上一个item的头部一致。
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Book book = mBookList.get(position);
holder.bodyTv.setText(book.getContent());
if (position == 0) {
// 首位元素的显示逻辑
holder.headerTv.setText(book.getName());
holder.headerTv.setVisibility(View.VISIBLE);
holder.itemView.setTag(FIRST_STICKY_TAG);
} else {
if (TextUtils.equals(book.getName(), mBookList.get(position - 1).getName())) {
// 如果相等,说明Name有一致的情况,隐藏头部标题,而这个itemView标记为没有粘结头部
holder.headerTv.setVisibility(View.GONE);
holder.itemView.setTag(NONE_STICKY_TAG);
} else {
// 如果不一致,说明需要一个新的头部
holder.headerTv.setText(book.getName());
holder.headerTv.setVisibility(View.VISIBLE);
holder.itemView.setTag(HAS_STICKY_TAG);
}
}
// 为itemView添加描述内容,用于为列表顶部展示的那个header赋值
holder.itemView.setContentDescription(book.getName());
}
复制代码
- 在Activity中滑动逻辑
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// 按像素位置取到列表中 最上面的那个itemView
View firstView = recyclerView.findChildViewUnder(headerTv.getMeasuredWidth() / 2, 5);
// 根据该itemView的ContentDes 来为最上面固定的那个header设置内容。
// 这也就是在绑定数据时,用header数据为itemview设置contentDES的作用
if (firstView != null && firstView.getContentDescription() != null) {
headerTv.setText(String.valueOf(firstView.getContentDescription()));
}
View secondView = recyclerView.findChildViewUnder(headerTv.getMeasuredWidth() / 2, headerTv.getMeasuredHeight() + 2);
if (secondView != null && secondView.getTag() != null) {
// 第二个itemview是否有header
int secondViewStatus = (int) secondView.getTag();
// 这个距离是 第二个带有header的item距离布局中固定的header的底部的距离。
// 大于0说明两个header还未接触,小于0说明需要将固定的header向上移动了。
// 因为已经是第二个header的列表的天下了。
int dealtY = secondView.getTop() - headerTv.getMeasuredHeight();
if (secondViewStatus==StickyGroupRecyclerViewAdapter.HAS_STICKY_TAG){
// 如果有header,就需要处理item自带的header和固定的header的位置关系。
if (secondView.getTop()>0){
// 在有header的情况下,top>0说明当前item自带的header还没有移动到list顶部。此时需要把固定的那个header 往上推一些top-headerHeight
headerTv.setTranslationY(dealtY);
}else {
// 如果item的header已经有一部分移出去了,固定的header就不要动了,已经完全遮住item的header了
headerTv.setTranslationY(0);
}
}else if (secondViewStatus==StickyGroupRecyclerViewAdapter.NONE_STICKY_TAG){
// 如果listitem没有header,那固定的header就不要动了
headerTv.setTranslationY(0);
}
}
}
});
复制代码
2.4 ItemTouchHelper介绍
RecyclerView中涉及到拖拽就需要使用ItemTouchHelper,这是support v7包提供的处理关于在RecyclerView上添加拖动排序与滑动删除的非常强大的工具类。
ItemTouchHelper的使用主要可分为两步: 第一步是继承ItemTouchHelper.Callback这个抽象类,并实现其中关于拖拽操作的抽象回调方法。 第二步是创建自定义的callback实例对象,并用该实例对象创建itemTouchHelper对象,再通过itemTouchHelper.attachToRecyclerView(mRecyclerView);
将 itemTouchHelper和我们的RecyclerView实例对象绑定在一起。
关键点就是 抽象回调方法的实现。
下面我们来看下有哪些常用的回调方法:
/**
* 设置滑动类型标记
* 如果是线性布局,则一般drag可让其支持UP|DOWN
* 如果是网格布局,则一般drag可让其支持UP|DOWN|LEFT|RIGHT 四个方向
* swipe状态可以设置LEFT|RIGHT
* 不允许该类操作则 可设置为0
* @param recyclerView
* @param viewHolder
* 上面两个入参,可用于根据列表类型或ITEM类型来让其支持不同的操作。
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
/***
* 当drag操作发生时会回调该方法,位置变动可交由adapter去处理,自己实现位置变动的逻辑。
*
* @param recyclerView
* @param viewHolder 正在拖动的item
* @param target 在移动方向上最近的那个item
* @return 如果有位置变动返回true 没有变动则返回false
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mDragViewAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* 当item滑动达到指定距离或者达到指定速度,都会回调该方法。
* 一般可在此处处理滑动删除的逻辑,需要自己在adapter中实现。
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
复制代码
以上是三个最常用的方法,还有其他一些会用到的方法这里也罗列一下:
/**
* 在长按时是否进入drag状态,当为false时,可以在外部调用mItemTouchHelper.startDrag(viewHolder);
* 来进入drag状态,比如说:通过item的一个按钮的点击事件来触发starDrag方法来进入drag状态。
*/
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 当item被drag或swipe选中时回调
* 此处可以对选中的item做一些状态的更改。
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// 只要item不是闲置状态,就为其设置背景
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundResource(R.drawable.item_selected);
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 标记当drag中的item移动到target正上方时,target是否变动位置。
* 默认为true,如果为false则target位置不会变动,拖拽结束原item会回到原来的位置
* @param recyclerView
* @param current
* @param target
* @return
*/
@Override
public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
return true;
}
/**
* 当拖拽或滑动完毕后会调用该方法,我们可以在此处还原一些状态。
* @param recyclerView
* @param viewHolder 拖拽或滑动的那个item
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
Log.d(TAG,"clearView item:"+viewHolder.getAdapterPosition());
viewHolder.itemView.setBackgroundResource(R.color.aqua);
super.clearView(recyclerView, viewHolder);
}
/**
* 当拖拽的item移动到下方item多少位置的时候触发onMove 方法,自己测试貌似至少要100% 才会触发移动,小于1f的值无效。
* 当大于1f时,需要达到指定比例的位置才会触发onMove 方法。
*/
@Override
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
return 1.5f;
}
复制代码
2.5 拖动Item
了解了ItemTouchHelper,实现拖动就简单了。首先我们需要定义一个接口,传入拖动的id和target的id
public interface ItemTouchHelperListener {
void onItemMove(int fromPosition, int toPosition);
}
复制代码
让我们的Adapter实现该接口
// 交换数据,只更新指定位置item
@Override
public void onItemMove(int fromPosition, int toPosition) {
Collections.swap(mBookList,fromPosition,toPosition);
notifyItemMoved(fromPosition, toPosition);
}
复制代码
实现我们自己定义的ItemTouchHelper
public class DragItemTouchHelper extends ItemTouchHelper.Callback {
private static final String TAG = DragItemTouchHelper.class.getSimpleName();
private DragViewAdapter mDragViewAdapter;
public DragItemTouchHelper(DragViewAdapter dragViewAdapter) {
mDragViewAdapter = dragViewAdapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Log.d(TAG, "onMove: " + viewHolder.toString() + " " + target.toString());
mDragViewAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// 只要item不是闲置状态,就为其设置背景
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundResource(R.drawable.item_selected);
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
viewHolder.itemView.setBackgroundResource(R.color.aqua);
super.clearView(recyclerView, viewHolder);
}
}
复制代码
最后在Activity或Fragment中实现控件的初始化逻辑。
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
DragViewAdapter adapter = new DragViewAdapter(this);
ItemTouchHelper.Callback callback = new DragItemTouchHelper(adapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
mRecyclerView.setAdapter(adapter);
adapter.setBookList(mData);
复制代码
2.6 滑动删除
滑动删除的实现方式和拖拽基本一样,关键步骤如下:
// 回调接口定义
public interface OnItemTouchHelperListener {
void onItemDelete(int position);
}
// 在adapter中实现删除item的回调
@Override
public void onItemDelete(int position) {
if (position < 0 || position > getItemCount()) {
return;
}
data.remove(position);
notifyItemRemoved(position);
}
// ItemTouchHelper.Callback中的关键实现
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;
int swipeFlags = ItemTouchHelper.LEFT;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mSwipeAdapter.onItemDelete(viewHolder.getAdapterPosition());
}
// 设置item选中时的背景色
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundResource(R.drawable.item_selected);
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
viewHolder.itemView.setBackgroundResource(R.drawable.item_normal);
super.clearView(recyclerView, viewHolder);
}
复制代码
2.7 下拉刷新
关于下拉刷新官方提供了SwipeRefreshLayout可用,在support.v4.widget中,使用也很简单,SwipeRefreshLayout直接包含列表或者ScrollView。
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_down_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_down_refresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
复制代码
以下代码模拟了下载事件
mSwipeRefreshLayout = findViewById(R.id.srl_down_refresh);
mSwipeRefreshLayout.setColorSchemeResources(
android.R.color.holo_red_light,
android.R.color.holo_orange_light,
android.R.color.holo_green_light,
android.R.color.holo_blue_light,
android.R.color.holo_purple
);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
},6000);
}
});
复制代码
2.8 双向滑动
双向滑动是指一个RecyclerView中包含一个竖向滚动的RecyclerView和一个横向滚动的RecyclerView。实现思路是将Item作为一个List。 主RecyclerView中包含两个元素,一个横向滚动的item,一个竖向滚动的item。一个列表中同时存在两种类型的item,就得有两种ViewHolder。 还需要创建类型标记。
public class SlideAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = SlideAdapter.class.getSimpleName();
private static final int TYPE_HORIZONTAL = 0;
private static final int TYPE_VERTICAL = 1;
private Context mContext;
private List<Integer> mTypeList = new ArrayList<>();
private List<String> mHorizontalList = new ArrayList<>();
private List<String> mVerticalList = new ArrayList<>();
public SlideAdapter(Context context, List<Integer> typeList) {
mContext = context;
mTypeList = typeList;
}
public void setHorizontalDataList(List<String> horizontalDataList) {
mHorizontalList = horizontalDataList;
notifyDataSetChanged();
}
public void setVerticalDataList(List<String> verticalDataList) {
mVerticalList = verticalDataList;
notifyDataSetChanged();
}
/**
* 多种类型的item就需要重写该方法,根据数据类型决定item类型。
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
if (mTypeList.get(position) == 0) { // 横向
return TYPE_HORIZONTAL;
} else if (mTypeList.get(position) == 1) { // 纵向
return TYPE_VERTICAL;
} else {
return super.getItemViewType(position);
}
}
/**
* 根据viewType创建viewholder,
* @param parent
* @param viewType 此处的type也是来自于getItemViewType方法
* @return
*/
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_HORIZONTAL) {
View viewHorizontal = LayoutInflater.from(mContext).inflate(R.layout.slide_horizontal_include, parent, false);
return new HorizontalViewHolder(viewHorizontal);
} else if (viewType == TYPE_VERTICAL) {
View viewVertical = LayoutInflater.from(mContext).inflate(R.layout.slide_vertical_include, parent, false);
return new VerticalViewHolder(viewVertical);
}
return null;
}
/**
* 根据不同类型绑定数据,其实就是创建子列表的过程。
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof HorizontalViewHolder) {
if (mHorizontalList != null) {
// 这里就是创建横向滚动的子RecyclerView 的过程。
SlideHorizontalAdapter horizontalAdapter = new SlideHorizontalAdapter(mContext, mHorizontalList);
LinearLayoutManager manager = new LinearLayoutManager(mContext);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
((HorizontalViewHolder) holder).rcvHorizontal.setLayoutManager(manager);
((HorizontalViewHolder) holder).rcvHorizontal.setHasFixedSize(true);
((HorizontalViewHolder) holder).rcvHorizontal.addItemDecoration(new DividerItemDecoration(mContext, DividerItemDecoration.HORIZONTAL));
((HorizontalViewHolder) holder).rcvHorizontal.setAdapter(horizontalAdapter);
horizontalAdapter.notifyDataSetChanged();
}
} else if (holder instanceof VerticalViewHolder) {
if (mVerticalList != null) {
SlideVerticalAdapter verticalAdapter = new SlideVerticalAdapter(mContext, mVerticalList);
((VerticalViewHolder) holder).rcvVertical.setLayoutManager(new LinearLayoutManager(mContext));
((VerticalViewHolder) holder).rcvVertical.setHasFixedSize(true);
((VerticalViewHolder) holder).rcvVertical.addItemDecoration(new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL));
((VerticalViewHolder) holder).rcvVertical.setAdapter(verticalAdapter);
verticalAdapter.notifyDataSetChanged();
}
}
}
@Override
public int getItemCount() {
return mTypeList.size();
}
public class HorizontalViewHolder extends RecyclerView.ViewHolder {
RecyclerView rcvHorizontal;
public HorizontalViewHolder(View itemView) {
super(itemView);
rcvHorizontal = itemView.findViewById(R.id.rcv_slide_horizontal);
}
}
public class VerticalViewHolder extends RecyclerView.ViewHolder {
RecyclerView rcvVertical;
public VerticalViewHolder(View itemView) {
super(itemView);
rcvVertical = itemView.findViewById(R.id.rcv_slide_vertical);
}
}
}
复制代码
2.9 收缩展开
item同样分为header和body,点击头部展开body,具体实现如下: expandedPosition 记录处于展开状态的item位置。 mViewHolder 保存处于展开状态的item。 isExpanded 记录当前item是否是展开的。
public void onBindViewHolder(@NonNull final ExpandCollapseViewHolder holder, int position) {
holder.tvTeam.setText(mList.get(position));
holder.tvTeamChild.setText(mList.get(position) + "的子内容");
// 判断展开的位置和当前位置是否相同,相同则认定为展开的true
final boolean isExpanded = position == expandedPosition;
// 如果是展开的则显示body区域,否则gone
holder.rlChild.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
holder.rlParent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 若有展开的holder,则让其关闭
if (mViewHolder != null) {
mViewHolder.rlChild.setVisibility(View.GONE);
// 更新展开的item
notifyItemChanged(expandedPosition);
}
// 如果本item是展开的,则重置标记;否则记录位置及holder
expandedPosition = isExpanded ? -1 : holder.getAdapterPosition();
mViewHolder = isExpanded ? null : holder;
// 更新当前item
notifyItemChanged(holder.getAdapterPosition());
}
});
}
复制代码