Saltar al contenido

Cómo agregar un RecyclerView dentro de otro RecyclerView

Buscamos por distintos sitios para darte la respuesta para tu inquietud, si tienes dudas puedes dejarnos tu inquietud y te responderemos sin falta.

Solución:

Me gustaría sugerir el uso de un solo RecyclerView y rellene los elementos de su lista de forma dinámica. Agregué un proyecto de github para describir cómo se puede hacer esto. Puede que le eches un vistazo. Si bien las otras soluciones funcionarán bien, me gustaría sugerir que esta es una forma mucho más rápida y eficiente de mostrar múltiples listas en una RecyclerView.

La idea es agregar lógica en su onCreateViewHolder y onBindViewHolder método para que pueda inflar la vista adecuada para las posiciones exactas en su RecyclerView.

También agregué un proyecto de muestra junto con esa wiki. Puede clonar y comprobar lo que hace. Para mayor comodidad, publico el adaptador que he utilizado.

public class DynamicListAdapter extends RecyclerView.Adapter 

    private static final int FOOTER_VIEW = 1;
    private static final int FIRST_LIST_ITEM_VIEW = 2;
    private static final int FIRST_LIST_HEADER_VIEW = 3;
    private static final int SECOND_LIST_ITEM_VIEW = 4;
    private static final int SECOND_LIST_HEADER_VIEW = 5;

    private ArrayList firstList = new ArrayList();
    private ArrayList secondList = new ArrayList();

    public DynamicListAdapter() 
    

    public void setFirstList(ArrayList firstList) 
        this.firstList = firstList;
    

    public void setSecondList(ArrayList secondList) 
        this.secondList = secondList;
    

    public class ViewHolder extends RecyclerView.ViewHolder 
        // List items of first list
        private TextView mTextDescription1;
        private TextView mListItemTitle1;

        // List items of second list
        private TextView mTextDescription2;
        private TextView mListItemTitle2;

        // Element of footer view
        private TextView footerTextView;

        public ViewHolder(final View itemView) 
            super(itemView);

            // Get the view of the elements of first list
            mTextDescription1 = (TextView) itemView.findViewById(R.id.description1);
            mListItemTitle1 = (TextView) itemView.findViewById(R.id.title1);

            // Get the view of the elements of second list
            mTextDescription2 = (TextView) itemView.findViewById(R.id.description2);
            mListItemTitle2 = (TextView) itemView.findViewById(R.id.title2);

            // Get the view of the footer elements
            footerTextView = (TextView) itemView.findViewById(R.id.footer);
        

        public void bindViewSecondList(int pos) 

            if (firstList == null) pos = pos - 1;
            else 
                if (firstList.size() == 0) pos = pos - 1;
                else pos = pos - firstList.size() - 2;
            

            final String description = secondList.get(pos).getDescription();
            final String title = secondList.get(pos).getTitle();

            mTextDescription2.setText(description);
            mListItemTitle2.setText(title);
        

        public void bindViewFirstList(int pos) 

            // Decrease pos by 1 as there is a header view now.
            pos = pos - 1;

            final String description = firstList.get(pos).getDescription();
            final String title = firstList.get(pos).getTitle();

            mTextDescription1.setText(description);
            mListItemTitle1.setText(title);
        

        public void bindViewFooter(int pos) 
            footerTextView.setText("This is footer");
        
    

    public class FooterViewHolder extends ViewHolder 
        public FooterViewHolder(View itemView) 
            super(itemView);
        
    

    private class FirstListHeaderViewHolder extends ViewHolder 
        public FirstListHeaderViewHolder(View itemView) 
            super(itemView);
        
    

    private class FirstListItemViewHolder extends ViewHolder 
        public FirstListItemViewHolder(View itemView) 
            super(itemView);
        
    

    private class SecondListHeaderViewHolder extends ViewHolder 
        public SecondListHeaderViewHolder(View itemView) 
            super(itemView);
        
    

    private class SecondListItemViewHolder extends ViewHolder 
        public SecondListItemViewHolder(View itemView) 
            super(itemView);
        
    

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 

        View v;

        if (viewType == FOOTER_VIEW) 
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_footer, parent, false);
            FooterViewHolder vh = new FooterViewHolder(v);
            return vh;

         else if (viewType == FIRST_LIST_ITEM_VIEW) 
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_first_list, parent, false);
            FirstListItemViewHolder vh = new FirstListItemViewHolder(v);
            return vh;

         else if (viewType == FIRST_LIST_HEADER_VIEW) 
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_first_list_header, parent, false);
            FirstListHeaderViewHolder vh = new FirstListHeaderViewHolder(v);
            return vh;

         else if (viewType == SECOND_LIST_HEADER_VIEW) 
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_second_list_header, parent, false);
            SecondListHeaderViewHolder vh = new SecondListHeaderViewHolder(v);
            return vh;

         else 
            // SECOND_LIST_ITEM_VIEW
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_second_list, parent, false);
            SecondListItemViewHolder vh = new SecondListItemViewHolder(v);
            return vh;
        
    

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) 

        try 
            if (holder instanceof SecondListItemViewHolder) 
                SecondListItemViewHolder vh = (SecondListItemViewHolder) holder;
                vh.bindViewSecondList(position);

             else if (holder instanceof FirstListHeaderViewHolder) 
                FirstListHeaderViewHolder vh = (FirstListHeaderViewHolder) holder;

             else if (holder instanceof FirstListItemViewHolder) 
                FirstListItemViewHolder vh = (FirstListItemViewHolder) holder;
                vh.bindViewFirstList(position);

             else if (holder instanceof SecondListHeaderViewHolder) 
                SecondListHeaderViewHolder vh = (SecondListHeaderViewHolder) holder;

             else if (holder instanceof FooterViewHolder) 
                FooterViewHolder vh = (FooterViewHolder) holder;
                vh.bindViewFooter(position);
            
         catch (Exception e) 
            e.printStackTrace();
        
    

    @Override
    public int getItemCount() 

        int firstListSize = 0;
        int secondListSize = 0;

        if (secondList == null && firstList == null) return 0;

        if (secondList != null)
            secondListSize = secondList.size();
        if (firstList != null)
            firstListSize = firstList.size();

        if (secondListSize > 0 && firstListSize > 0)
            return 1 + firstListSize + 1 + secondListSize + 1;   // first list header, first list size, second list header , second list size, footer
        else if (secondListSize > 0 && firstListSize == 0)
            return 1 + secondListSize + 1;                       // second list header, second list size, footer
        else if (secondListSize == 0 && firstListSize > 0)
            return 1 + firstListSize;                            // first list header , first list size
        else return 0;
    

    @Override
    public int getItemViewType(int position) 

        int firstListSize = 0;
        int secondListSize = 0;

        if (secondList == null && firstList == null)
            return super.getItemViewType(position);

        if (secondList != null)
            secondListSize = secondList.size();
        if (firstList != null)
            firstListSize = firstList.size();

        if (secondListSize > 0 && firstListSize > 0) 
            if (position == 0) return FIRST_LIST_HEADER_VIEW;
            else if (position == firstListSize + 1)
                return SECOND_LIST_HEADER_VIEW;
            else if (position == secondListSize + 1 + firstListSize + 1)
                return FOOTER_VIEW;
            else if (position > firstListSize + 1)
                return SECOND_LIST_ITEM_VIEW;
            else return FIRST_LIST_ITEM_VIEW;

         else if (secondListSize > 0 && firstListSize == 0) 
            if (position == 0) return SECOND_LIST_HEADER_VIEW;
            else if (position == secondListSize + 1) return FOOTER_VIEW;
            else return SECOND_LIST_ITEM_VIEW;

         else if (secondListSize == 0 && firstListSize > 0) 
            if (position == 0) return FIRST_LIST_HEADER_VIEW;
            else return FIRST_LIST_ITEM_VIEW;
        

        return super.getItemViewType(position);
    

Hay otra forma de mantener sus elementos en un solo ArrayList de objetos para que pueda establecer un atributo que etiquete los elementos para indicar qué elemento es de la primera lista y cuál pertenece a la segunda lista. Entonces pasa eso ArrayList en tu RecyclerView y luego implementar la lógica dentro del adaptador para poblarlos dinámicamente.

Espero que ayude.

Me encontré con un problema similar hace un tiempo y lo que estaba sucediendo en mi caso era que la vista del reciclador externo funcionaba perfectamente bien, pero el adaptador de la vista del reciclador interno / segundo tenía problemas menores, todos los métodos como el constructor se iniciaron e incluso el método getCount () se estaba llamando, aunque los métodos finales responsables de generar la vista, es decir.

1. Los métodos onBindViewHolder () nunca fueron llamados. -> Problema 1.

2. Cuando finalmente se llamó, nunca mostró la lista de elementos / filas de la vista del reciclador. -> Problema 2.

Razón por la que sucedió esto :: Cuando coloca una vista de reciclador dentro de otra vista de reciclador, la altura de la primera vista de reciclador / exterior no se ajusta automáticamente. Se define cuando se crea la primera vista / exterior y luego permanece fija. En ese punto, su segunda vista de reciclador interno aún no ha cargado sus elementos y, por lo tanto, su altura se establece en cero y nunca cambia incluso cuando obtiene datos. Luego, cuando onBindViewHolder () en su segunda vista de reciclador interno es llamado, obtiene elementos pero no tiene espacio para mostrarlos porque su altura sigue siendo cero. Por lo tanto, los elementos en la segunda vista del reciclador nunca se muestran incluso cuando onBindViewHolder () los ha agregado.

Solución :: tienes que crear tu LinearLayoutManager personalizado para la segunda vista del reciclador y eso es todo. Para crear su propio LinearLayoutManager: Crea una clase Java con el nombre CustomLinearLayoutManager y pegue el siguiente código en él. NO SE REQUIEREN CAMBIOS

public class CustomLinearLayoutManager extends LinearLayoutManager 

    private static final String TAG = CustomLinearLayoutManager.class.getSimpleName();

    public CustomLinearLayoutManager(Context context) 
        super(context);

    

    public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) 
        super(context, orientation, reverseLayout);
    

    private int[] mMeasuredDimension = new int[2];

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) 

        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);

        int width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) 
            measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);


            if (getOrientation() == HORIZONTAL) 
                width = width + mMeasuredDimension[0];
                if (i == 0) 
                    height = mMeasuredDimension[1];
                
             else 
                height = height + mMeasuredDimension[1];
                if (i == 0) 
                    width = mMeasuredDimension[0];
                
            
        
        switch (widthMode) 
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        

        switch (heightMode) 
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        

        setMeasuredDimension(width, height);
    

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) 
        try 
            View view = recycler.getViewForPosition(position);

            if (view != null) 
                RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();

                int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                        getPaddingLeft() + getPaddingRight(), p.width);

                int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                        getPaddingTop() + getPaddingBottom(), p.height);

                view.measure(childWidthSpec, childHeightSpec);
                measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
                measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
                recycler.recycleView(view);
            
         catch (Exception e) 
            e.printStackTrace();
        
    

puede utilizar LayoutInflater para inflar sus datos dinámicos como un archivo de diseño.

ACTUALIZAR : primero cree un LinearLayout dentro del diseño de su CardView y asígnele una ID. después de eso, cree un archivo de diseño que desee inflar. por fin en tu onBindViewHolder método en su clase "RAdaper". escribe estos códigos:

  mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

  view = mInflater.inflate(R.layout.my_list_custom_row, parent, false);

después de eso, puede inicializar datos y ClickListeners con su RAdapter Data. Espero eso ayude.

esto y esto puede ser útil 🙂

Te mostramos las reseñas y valoraciones de los lectores

Tienes la opción de apoyar nuestra tarea ejecutando un comentario o puntuándolo te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *