1. Basic use

RecyclerView needs to inherit recyclerView. Adapter and recyclerView. ViewHolder.

  1. 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
  2. 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
  3. 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

  1. 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
  1. 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
  1. 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
  1. 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