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());
}
});
}
複製程式碼