1. Basic use
RecyclerView needs to inherit recyclerView. Adapter and recyclerView. ViewHolder.
-
Implement the ViewHolder, which is the child control to be used in the initial Item as the inner class of the 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); }}Copy the code
-
To implement Adapter, there are three important methods: onCreateViewHolder creates the ViewHolder instance, onBindViewHolder binds data to the ViewHolder instance, and getItemCount gets the number of lists.
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(a) { 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); }}}Copy the code
-
To configure controls in an Activity or Fragment, you can set the horizontal layout of items, vertical layout, and grid layout
// Configure the layout mode LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(linearLayoutManager); // Initialize the adapter mAdapter = new VerticalRecyclerViewAdapter(this); mAdapter.setData(list); // Set Adapter for RecyclerView mRecyclerView.setAdapter(mAdapter); // Set up the grid layout GridLayoutManager gridLayoutManager=new GridLayoutManager(this.3); // Reset the number of columns gridLayoutManager.setSpanCount(2); Copy the code
2. Advanced use
2.1 Click Event
There are two ways to monitor the click event of Item in RecyclerView. The first way is to process the click event in Adapter, and the second way is to realize the click event processing outside.
// Define the interface
public interface OnItemClickListener {
void onItemClick(View view, Book book);
}
// Listener injection, either construct-time injection or setter injection.
private Context mContext;
private OnItemClickListener mOnItemClickListener;
public ClickRecyclerViewAdapter(Context context, OnItemClickListener onItemClickListener) {
mContext = context;
mOnItemClickListener = onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
// Data binding and event listening for specific controls
public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {
holder.titleBtn.setText("Button:" + (position + 1));
holder.titleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "Implement click processing logic in 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)); }}); }Event-handling logic can be injected when the Adapter is initialized
ClickRecyclerViewAdapter adapter=new ClickRecyclerViewAdapter(this.new ClickRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, Book book) {
Snackbar.make(view,"Externally injected click logic:"+view.getId(),Snackbar.LENGTH_SHORT).setAction("Action".null).show(); }});Copy the code
2.2 grouping
There are many ways to implement grouping. The simplest way is to write the header and body in the same layout and compare the data when binding. If the data is in the same group as the data in the previous position, that is, hide the header of this Item. Note: This requires that the incoming data be grouped. The main implementation is as follows: Item layout is as follows
<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>
Copy the code
The data grouping logic is as follows:
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.titleTv.setText(data.get(position).getName());
holder.contentTv.setText(data.get(position).getContent());
// title is 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); }}}Copy the code
2.3 Suspension ceiling
The realization of suspension suction top also needs to use grouping. The specific idea is to fix a header layout at the top of RecyclerView. When the header in the list is rolled to here, the fixed header will slide up. When the header slides out, replace it with the next header
- RecyclerView layout, RecyclerView and header together.
<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>
Copy the code
- The Item layout file is the same as the grouping implementation.
<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>
Copy the code
- Group displays and sets tag bits for items
public static final int FIRST_STICKY_TAG = 1;// Is the first element
public static final int HAS_STICKY_TAG = 2;// This Item has a Header
public static final int NONE_STICKY_TAG = 3;// This Item has no Header
/** * The header and the body are displayed separately, depending on whether the header of the current item matches the header of the previous 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) {
// Display logic for the first element
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())) {
// If it is equal, the Name is consistent, and the header title is hidden, while the itemView marks no binding header
holder.headerTv.setVisibility(View.GONE);
holder.itemView.setTag(NONE_STICKY_TAG);
} else {
// If not, a new header is requiredholder.headerTv.setText(book.getName()); holder.headerTv.setVisibility(View.VISIBLE); holder.itemView.setTag(HAS_STICKY_TAG); }}// Add a description to the itemView to assign to the header shown at the top of the list
holder.itemView.setContentDescription(book.getName());
}
Copy the code
- Slide logic in the Activity
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Fetch the top itemView by pixel position
View firstView = recyclerView.findChildViewUnder(headerTv.getMeasuredWidth() / 2.5);
// Set the contents of the top fixed header according to the ContentDes of the itemView.
// Use the header data to set the contentDES for the ItemView when binding data
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) {
// Does the second ItemView have a header
int secondViewStatus = (int) secondView.getTag();
// This distance is the distance between the second header item and the bottom of the fixed header in the layout.
If the value is greater than 0, the two headers are not touching yet. If the value is less than 0, the fixed header needs to be moved up.
// Because the second header is already in the list.
int dealtY = secondView.getTop() - headerTv.getMeasuredHeight();
if (secondViewStatus==StickyGroupRecyclerViewAdapter.HAS_STICKY_TAG){
// If there is a header, we need to handle the position relationship between the built-in header and the fixed header.
if (secondView.getTop()>0) {// In the case of headers, top>0 indicates that the header of the current item has not been moved to the top of the list. So we need to push that fixed header up a little bit
headerTv.setTranslationY(dealtY);
}else {
// If part of the header of the item has already been moved out, the fixed header should not be moved. It completely covers the item header
headerTv.setTranslationY(0); }}else if (secondViewStatus==StickyGroupRecyclerViewAdapter.NONE_STICKY_TAG){
// If listitem does not have a header, leave the fixed header untouched
headerTv.setTranslationY(0); }}}});Copy the code
2.4 introduce ItemTouchHelper
For RecyclerView drag-and-drop, you need to use ItemTouchHelper, which is a very powerful tool class for adding drag-and-sort and sliding deletes to RecyclerView.
The first step is to inherit the abstract ItemTouchHelper.Callback class and implement its abstract Callback method for drag-and-drop operations. The second step is to create a custom callback instance objects, and the instance objects create itemTouchHelper object, through itemTouchHelper. AttachToRecyclerView (mRecyclerView); Bind itemTouchHelper to our RecyclerView instance object.
The key point is to abstract the implementation of the callback method.
Let’s take a look at some common callback methods:
/ * * * set sliding type tag * if it is a linear layout, general drag allows its support UP | DOWN * if it is a grid layout, General drag allows its support UP | DOWN | LEFT | RIGHT four swipe state can set the LEFT | RIGHT direction * * does not allow this kind of operation can be set to 0 *@param recyclerView
* @paramViewHolder * The two entries above can be used to support different operations based on the list type or ITEM type. *@return* /
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
/*** * This method is called back when the drag operation occurs, and the position change can be handled by Adapter to implement the logic of the position change itself. * *@param recyclerView
* @paramViewHolder Item * that is being dragged@paramTarget Specifies the closest item * in the direction of movement@returnReturn true if there is a position change and false */ if there is no change
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mDragViewAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/** * this method is called when item slides a specified distance or a specified speed. * The logic that can normally handle sliding deletes here needs to be implemented in Adapter itself. *@param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
Copy the code
These are the three most commonly used methods, and there are a few others that will be used:
/ * * * in a long time whether to enter a state of drag, when is false, can be called outside mItemTouchHelper. StartDrag (viewHolder); * to enter the drag state, for example, by clicking on a button on an item that triggers the starDrag method. * /
public boolean isLongPressDragEnabled(a) {
return true;
}
/** * Callback when an item is selected by drag or swipe * Here you can make some state changes to the selected item. *@param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// Set the background for the item as long as it is not idle
if(actionState ! = ItemTouchHelper.ACTION_STATE_IDLE) { viewHolder.itemView.setBackgroundResource(R.drawable.item_selected); }super.onSelectedChanged(viewHolder, actionState);
}
/** * flag whether target moves when the item in drag moves directly above target. * Default is true, if false the target position does not change, the drag end item will return to the original position *@param recyclerView
* @param current
* @param target
* @return* /
@Override
public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
return true;
}
/** * this method is called when the drag or slide is complete, and we can restore some state here. *@param recyclerView
* @paramViewHolder the item to drag or slide
@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);
}
/** * The onMove method is triggered when the dragged item moves to the lower part of the item. * When the value is greater than 1f, the onMove method is triggered only when the specified ratio is reached. * /
@Override
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
return 1.5 f;
}
Copy the code
2.5 drag the Item
Now that you know ItemTouchHelper, it’s easy to drag. First we need to define an interface, passing in the drag ID and the TARGET ID
public interface ItemTouchHelperListener {
void onItemMove(int fromPosition, int toPosition);
}
Copy the code
Let our Adapter implement this interface
// Update only the specified position item
@Override
public void onItemMove(int fromPosition, int toPosition) {
Collections.swap(mBookList,fromPosition,toPosition);
notifyItemMoved(fromPosition, toPosition);
}
Copy the code
Implement our own 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(a) {
return true;
}
@Override
public boolean isItemViewSwipeEnabled(a) {
return false;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// Set the background for the item as long as it is not idle
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); }}Copy the code
Finally, implement the control’s initialization logic in an Activity or 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);
Copy the code
2.6 Sliding Deletion
The implementation of sliding deletion is basically the same as drag and drop. The key steps are as follows:
// Callback interface definition
public interface OnItemTouchHelperListener {
void onItemDelete(int position);
}
// Implement the delete item callback in adapter
@Override
public void onItemDelete(int position) {
if (position < 0 || position > getItemCount()) {
return;
}
data.remove(position);
notifyItemRemoved(position);
}
// Key implementation in 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());
}
// Set the background color when item is selected
@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);
}
Copy the code
2.7 Drop-down Refresh
SwipeRefreshLayout is also available in support.v4.widget. SwipeRefreshLayout directly contains lists or scrollViews.
<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>
Copy the code
The following code emulates the download event
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(a) {
new Handler().postDelayed(new Runnable() {
@Override
public void run(a) {
mSwipeRefreshLayout.setRefreshing(false); }},6000); }});Copy the code
2.8 Bidirectional sliding
Two-way sliding refers to a RecyclerView contains a vertical rolling RecyclerView and a horizontal rolling RecyclerView. The idea is to treat Item as a List. The main RecyclerView contains two elements, a horizontal scrolling item and a vertical scrolling item. If there are two types of items in a list, there must be two viewholders. You also need to create type tags.
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();
}
/** * If there are multiple types of item, we need to override this method to determine the type of item based on the data type. *@param position
* @return* /
@Override
public int getItemViewType(int position) {
if (mTypeList.get(position) == 0) { / / lateral
return TYPE_HORIZONTAL;
} else if (mTypeList.get(position) == 1) { / / the longitudinal
return TYPE_VERTICAL;
} else {
return super.getItemViewType(position); }}/** create viewholder based on viewType, *@param parent
* @paramViewType Here also comes from the getItemViewType method *@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;
}
/** * The process of creating sublists by binding data to different types. *@param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof HorizontalViewHolder) {
if(mHorizontalList ! =null) {
// Create a subrecyclerView for horizontal scrolling.
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(newDividerItemDecoration(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(newDividerItemDecoration(mContext, DividerItemDecoration.VERTICAL)); ((VerticalViewHolder) holder).rcvVertical.setAdapter(verticalAdapter); verticalAdapter.notifyDataSetChanged(); }}}@Override
public int getItemCount(a) {
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); }}}Copy the code
2.9 Contraction expansion
Item can also be divided into header and body. Click the header to expand the body. The specific implementation is as follows: expandedPosition Records the position of the item in the expanded state. MViewHolder holds the expanded item. IsExpanded records whether the current item isExpanded.
public void onBindViewHolder(@NonNull final ExpandCollapseViewHolder holder, int position) {
holder.tvTeam.setText(mList.get(position));
holder.tvTeamChild.setText(mList.get(position) + "Subcontents of");
// Determine whether the expansion position is the same as the current position, which is considered true of the expansion
final boolean isExpanded = position == expandedPosition;
// Display the body field if it is expanded, otherwise gone
holder.rlChild.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
holder.rlParent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// If there is an expanded holder, close it
if(mViewHolder ! =null) {
mViewHolder.rlChild.setVisibility(View.GONE);
// Update the expanded item
notifyItemChanged(expandedPosition);
}
// If this item is expanded, reset the flag; Otherwise record position and holder
expandedPosition = isExpanded ? -1 : holder.getAdapterPosition();
mViewHolder = isExpanded ? null : holder;
// Update current itemnotifyItemChanged(holder.getAdapterPosition()); }}); }Copy the code