Làm cách nào để tạo RecyclerView với nhiều kiểu xem?


864

Từ https://developer.android.com/preview/m vật liệu / ui-widgets.html

Khi chúng ta tạo, RecyclerView.Adapterchúng ta phải xác định ViewHolderrằng sẽ liên kết với bộ điều hợp.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private String[] mDataset;

    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mTextView;
        public ViewHolder(TextView v) {
            super(v);
            mTextView = v;
        }
    }

    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.some_layout, parent, false);

        //findViewById...

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.mTextView.setText(mDataset[position]);
    }

    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

Vì vậy, có thể tạo RecyclerViewvới nhiều kiểu xem không?


5
Trên đầu câu trả lời của Anton, hãy xem câu trả lời của tôi ở đây: stackoverflow.com/questions/25914003/ory
ticofab

Kiểm tra các liên kết này cũng có thể hữu ích cho bạn stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

1
Hướng dẫn tốt ở đây: guide.codepath.com/android/ từ
Gene Bo

Kiểm tra các liên kết này có khả thi stackoverflow.com/questions/39971350/ cấp Nếu có vấn đề hơn xin vui lòng cho tôi biết
Ravindra Kushwaha

Thư viện tuyệt vời để triển khai nó github.com/vivchar/RendererRecyclerViewAd CHƯƠNG
Vitaly

Câu trả lời:


1269

Vâng nó có thể. Chỉ cần thực hiện getItemViewType () và chăm sóc viewTypetham số trong onCreateViewHolder().

Vì vậy, bạn làm một cái gì đó như:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    class ViewHolder0 extends RecyclerView.ViewHolder {
        ...
        public ViewHolder0(View itemView){
        ...
        }
    }

    class ViewHolder2 extends RecyclerView.ViewHolder {
        ...
        public ViewHolder2(View itemView){
        ...
    }

    @Override
    public int getItemViewType(int position) {
        // Just as an example, return 0 or 2 depending on position
        // Note that unlike in ListView adapters, types don't have to be contiguous
        return position % 2 * 2;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case 0: return new ViewHolder0(...);
             case 2: return new ViewHolder2(...);
             ...
         }
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
        switch (holder.getItemViewType()) {
            case 0:
                ViewHolder0 viewHolder0 = (ViewHolder0)holder;
                ...
                break;

            case 2:
                ViewHolder2 viewHolder2 = (ViewHolder2)holder;
                ...
                break;
        }
    }
}

3
Đó là quan điểm của tôi vì chỉ có một ViewHolder có sẵn trong một RecyclerView. Chương trình bạn sẽ thêm nhiều vào nó như thế nào?
Pongpat

48
Sau đó, bạn phải bỏ kiểu người xem trong phương thức onBindViewHolder () mà tôi nghĩ rằng nó đánh bại mục đích của loại chung. Nhân tiện, cảm ơn bạn đã trả lời.
Pongpat

32
Bạn có thể tạo BaseHolder và mở rộng nó cho tất cả các loại yêu cầu. Sau đó thêm một setData trừu tượng, sẽ được ghi đè (overrode?) Trong các chủ sở hữu triển khai. Bằng cách này, bạn để cho ngôn ngữ xử lý sự khác biệt loại. Mặc dù nó chỉ hoạt động nếu bạn có một bộ dữ liệu duy nhất mà tất cả các mục danh sách có thể diễn giải.
DariusL

2
Những gì về tập tin bố trí khác nhau? Tôi muốn thay đổi bố cục trên optionMenuItem. Làm thế nào nó có thể? @AntonSavin
Pratik Butani

5
ViewHolders của bạn sẽ tĩnh nếu chúng nằm trong Bộ điều hợp RecyclerView của bạn
Samer

88

Nếu bố cục cho các kiểu xem chỉ là một vài và logic logic ràng buộc là đơn giản, hãy làm theo giải pháp của Anton.
Nhưng mã sẽ lộn xộn nếu bạn cần quản lý các bố cục phức tạp và logic logic ràng buộc.

Tôi tin rằng giải pháp sau đây sẽ hữu ích cho những người cần xử lý các kiểu xem phức tạp.

Lớp DataBinder cơ sở

abstract public class DataBinder<T extends RecyclerView.ViewHolder> {

    private DataBindAdapter mDataBindAdapter;

    public DataBinder(DataBindAdapter dataBindAdapter) {
        mDataBindAdapter = dataBindAdapter;
    }

    abstract public T newViewHolder(ViewGroup parent);

    abstract public void bindViewHolder(T holder, int position);

    abstract public int getItemCount();

......

}

Các hàm cần thiết để định nghĩa trong lớp này khá giống với lớp bộ điều hợp khi tạo kiểu xem đơn.
Đối với mỗi kiểu xem, hãy tạo lớp bằng cách mở rộng DataBinder này.

Lớp DataBinder mẫu

public class Sample1Binder extends DataBinder<Sample1Binder.ViewHolder> {

    private List<String> mDataSet = new ArrayList();

    public Sample1Binder(DataBindAdapter dataBindAdapter) {
        super(dataBindAdapter);
    }

    @Override
    public ViewHolder newViewHolder(ViewGroup parent) {
        View view = LayoutInflater.from(parent.getContext()).inflate(
            R.layout.layout_sample1, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void bindViewHolder(ViewHolder holder, int position) {
        String title = mDataSet.get(position);
        holder.mTitleText.setText(title);
    }

    @Override
    public int getItemCount() {
        return mDataSet.size();
    }

    public void setDataSet(List<String> dataSet) {
        mDataSet.addAll(dataSet);
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        TextView mTitleText;

        public ViewHolder(View view) {
            super(view);
            mTitleText = (TextView) view.findViewById(R.id.title_type1);
        }
    }
}

Để quản lý các lớp DataBinder, hãy tạo lớp bộ điều hợp.

Lớp DataBindAd CHƯƠNG cơ sở

abstract public class DataBindAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return getDataBinder(viewType).newViewHolder(parent);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        int binderPosition = getBinderPosition(position);
        getDataBinder(viewHolder.getItemViewType()).bindViewHolder(viewHolder, binderPosition);
    }

    @Override
    public abstract int getItemCount();

    @Override
    public abstract int getItemViewType(int position);

    public abstract <T extends DataBinder> T getDataBinder(int viewType);

    public abstract int getPosition(DataBinder binder, int binderPosition);

    public abstract int getBinderPosition(int position);

......

}

Tạo lớp bằng cách mở rộng lớp cơ sở này, sau đó khởi tạo các lớp DataBinder và ghi đè các phương thức trừu tượng

  1. getItemCount
    Trả lại tổng số mục của DataBinder

  2. getItemViewType
    Xác định logic ánh xạ giữa vị trí bộ điều hợp và kiểu xem.

  3. getDataBinder
    Trả về phiên bản DataBinder dựa trên kiểu xem

  4. getP vị trí
    Xác định logic chuyển đổi sang vị trí bộ điều hợp từ vị trí trong DataBinder được chỉ định

  5. getBinderPocation
    Xác định chuyển đổi logic sang vị trí trong DataBinder từ vị trí bộ điều hợp

Hy vọng giải pháp này sẽ hữu ích.
Tôi đã để lại chi tiết giải pháp và mẫu trong GitHub, vì vậy vui lòng tham khảo liên kết sau nếu bạn cần.
https://github.com/yqritc/RecyclerView-Mult MônViewTypesAd CHƯƠNG


4
Tôi hơi bối rối bởi mã của bạn, có lẽ bạn có thể giúp tôi, tôi không muốn các quan điểm của tôi được xác định bởi các vị trí trong danh sách mà bởi các chế độ xem của họ. Nó xuất hiện như thể các khung nhìn trong mã của bạn được xác định dựa trên vị trí của chúng tức là. vì vậy nếu im ở vị trí 1, chế độ xem 1 được hiển thị, vị trí 3, chế độ xem 3 được hiển thị và mọi thứ khác hiển thị chế độ xem của vị trí 2. Tôi không muốn dựa trên quan điểm của mình về các vị trí nhưng dựa trên chế độ xem - vì vậy nếu tôi chỉ định loại chế độ xem là hình ảnh, nó sẽ hiển thị hình ảnh. Làm thế nào tôi có thể làm điều đó?
Simon

Xin lỗi, tôi không thể hiểu hết câu hỏi của bạn ... nhưng bạn cần phải viết logic ở đâu đó để ràng buộc vị trí và chế độ xem.
yqritc

1
mã này không bị nhầm lẫn, đây là mẫu RecyclerView Adaptor và điều này nên được loại trừ như câu trả lời đúng của câu hỏi. Theo liên kết của @yqritc, dành một ít thời gian để khám phá và bạn sẽ có mẫu hoàn hảo cho RecyclerView với các kiểu bố cục khác nhau.
Stoycho Andreev

Mới đây, public class DataBinder<T extends RecyclerView.ViewHolder>ai đó có thể cho tôi biết cái gì <T someClass>được gọi không, vì vậy tôi có thể google nếu tôi nhận được thuật ngữ này. Ngoài ra khi tôi nói abstract public class DataBinder<T extends RecyclerView.ViewHolder>điều đó có nghĩa là lớp này là loại ViewHolder, vì vậy trong kết quả, mỗi lớp mở rộng lớp này sẽ là loại viewHolderđó là ý tưởng?
rgv 16/07/2015

1
@cesards bạn đã khiến tôi phải làm mới kiến ​​thức của mình một lần nữa về đa hình lol .... Java không tệ
Paul Okeke

37

Dưới đây không phải là mã giả và tôi đã thử nó và nó đã làm việc cho tôi.

Tôi muốn tạo một headerview trong recyclerview của mình và sau đó hiển thị danh sách các hình ảnh bên dưới tiêu đề mà người dùng có thể nhấp vào.

Tôi đã sử dụng một vài công tắc trong mã của mình, không biết đó có phải là cách hiệu quả nhất để làm việc này hay không, vì vậy hãy đưa ra nhận xét của bạn:

   public class ViewHolder extends RecyclerView.ViewHolder{

        //These are the general elements in the RecyclerView
        public TextView place;
        public ImageView pics;

        //This is the Header on the Recycler (viewType = 0)
        public TextView name, description;

        //This constructor would switch what to findViewBy according to the type of viewType
        public ViewHolder(View v, int viewType) {
            super(v);
            if (viewType == 0) {
                name = (TextView) v.findViewById(R.id.name);
                decsription = (TextView) v.findViewById(R.id.description);
            } else if (viewType == 1) {
                place = (TextView) v.findViewById(R.id.place);
                pics = (ImageView) v.findViewById(R.id.pics);
            }
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent,
                                         int viewType)
    {
        View v;
        ViewHolder vh;
        // create a new view
        switch (viewType) {
            case 0: //This would be the header view in my Recycler
                v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recyclerview_welcome, parent, false);
                vh = new ViewHolder(v,viewType);
                return  vh;
            default: //This would be the normal list with the pictures of the places in the world
                v = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.recyclerview_picture, parent, false);
                vh = new ViewHolder(v, viewType);
                v.setOnClickListener(new View.OnClickListener(){

                    @Override
                    public void onClick(View v) {
                        Intent intent = new Intent(mContext, nextActivity.class);
                        intent.putExtra("ListNo",mRecyclerView.getChildPosition(v));
                        mContext.startActivity(intent);
                    }
                });
                return vh;
        }
    }

    //Overriden so that I can display custom rows in the recyclerview
    @Override
    public int getItemViewType(int position) {
        int viewType = 1; //Default is 1
        if (position == 0) viewType = 0; //if zero, it will be a header view
        return viewType;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //position == 0 means its the info header view on the Recycler
        if (position == 0) {
            holder.name.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext,"name clicked", Toast.LENGTH_SHORT).show();
                }
            });
            holder.description.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext,"description clicked", Toast.LENGTH_SHORT).show();
                }
            });
            //this means it is beyond the headerview now as it is no longer 0. For testing purposes, I'm alternating between two pics for now
        } else if (position > 0) {
           holder.place.setText(mDataset[position]);
            if (position % 2 == 0) {
               holder.pics.setImageDrawable(mContext.getResources().getDrawable(R.drawable.pic1));
            }
            if (position % 2 == 1) {
                holder.pics.setImageDrawable(mContext.getResources().getDrawable(R.drawable.pic2));
            }

        }
    }

Đây là một điều tốt đẹp, nếu tôi muốn nhiều tiêu đề ở các vị trí động thì sao? Nói, một danh sách các mục với các tiêu đề xác định danh mục. Giải pháp của bạn dường như sẽ yêu cầu các tiêu đề đặc biệt phải ở các vị trí int được xác định trước.
Bassinator

22

Vâng, nó là có thể.

Viết một chủ sở hữu xem chung:

    public abstract class GenericViewHolder extends RecyclerView.ViewHolder
{
    public GenericViewHolder(View itemView) {
        super(itemView);
    }

    public abstract  void setDataOnView(int position);
}

sau đó tạo chủ sở hữu chế độ xem của bạn và làm cho chúng mở rộng GenericViewHolder. Ví dụ: cái này:

     public class SectionViewHolder extends GenericViewHolder{
    public final View mView;
    public final TextView dividerTxtV;

    public SectionViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
        dividerTxtV = (TextView) mView.findViewById(R.id.dividerTxtV);
    }

    @Override
    public void setDataOnView(int position) {
        try {
            String title= sections.get(position);
            if(title!= null)
                this.dividerTxtV.setText(title);
        }catch (Exception e){
            new CustomError("Error!"+e.getMessage(), null, false, null, e);
        }
    }
}

sau đó lớp RecyclerView.Ad CHƯƠNG sẽ giống như thế này:

public class MyClassRecyclerViewAdapter extends RecyclerView.Adapter<MyClassRecyclerViewAdapter.GenericViewHolder> {

@Override
public int getItemViewType(int position) {
     // depends on your problem
     switch (position) {
         case : return VIEW_TYPE1;
         case : return VIEW_TYPE2;
         ...
     }
}

    @Override
   public GenericViewHolder onCreateViewHolder(ViewGroup parent, int viewType)  {
    View view;
    if(viewType == VIEW_TYPE1){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout1, parent, false);
        return new SectionViewHolder(view);
    }else if( viewType == VIEW_TYPE2){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout2, parent, false);
        return new OtherViewHolder(view);
    }
    // Cont. other view holders ...
    return null;
   }

@Override
public void onBindViewHolder(GenericViewHolder holder, int position) {
    holder.setDataOnView(position);
}

Làm thế nào để sử dụng sau đó trong một hoạt động? Các loại nên được thông qua phương pháp?
skm

Làm thế nào để sử dụng Bộ chuyển đổi này trong Hoạt động? Và làm thế nào để nó nhận ra Loại nào trong danh sách
skm

20

Tạo ViewHolder khác nhau cho bố cục khác nhau

nhập mô tả hình ảnh ở đây
RecyclerView có thể có bất kỳ số lượng người xem nào bạn muốn nhưng để dễ đọc hơn, hãy xem cách tạo một cái có hai ViewHolders.

Nó có thể được thực hiện trong ba bước đơn giản

  1. Ghi đè public int getItemViewType(int position)
  2. Trả về các ViewHolders khác nhau dựa trên ViewType trong onCreateViewHolder()phương thức
  3. Chế độ xem dân số dựa trên itemViewType trong onBindViewHolder()phương thức

Đây là một đoạn mã nhỏ

public class YourListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

   private static final int LAYOUT_ONE= 0;
   private static final int LAYOUT_TWO= 1;

   @Override
   public int getItemViewType(int position)
   {
      if(position==0)
        return LAYOUT_ONE;
      else
        return LAYOUT_TWO;
   }

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

      View view =null;
      RecyclerView.ViewHolder viewHolder = null;

      if(viewType==LAYOUT_ONE)
      {
          view = LayoutInflater.from(parent.getContext()).inflate(R.layout.one,parent,false);
          viewHolder = new ViewHolderOne(view);
      }
      else
      {
          view = LayoutInflater.from(parent.getContext()).inflate(R.layout.two,parent,false);
          viewHolder= new ViewHolderTwo(view);
      }

      return viewHolder;
   }

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

      if(holder.getItemViewType()== LAYOUT_ONE)
      {
            // Typecast Viewholder 
            // Set Viewholder properties 
            // Add any click listener if any 
      }
      else {

        ViewHolderOne vaultItemHolder = (ViewHolderOne) holder;
        vaultItemHolder.name.setText(displayText);
        vaultItemHolder.name.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
            .......
           }
         });

       }

   }

  //****************  VIEW HOLDER 1 ******************//

   public class ViewHolderOne extends RecyclerView.ViewHolder {

      public TextView name;

      public ViewHolderOne(View itemView) {
         super(itemView);
         name = (TextView)itemView.findViewById(R.id.displayName);
     }
   }


   //****************  VIEW HOLDER 2 ******************//

   public class ViewHolderTwo extends RecyclerView.ViewHolder{

      public ViewHolderTwo(View itemView) {
         super(itemView);

        ..... Do something
      }
   }
}

getItemViewType (vị trí int) là khóa

Theo tôi, điểm khởi đầu để tạo ra loại recyclerView này là kiến ​​thức về phương pháp này. Vì phương thức này là tùy chọn để ghi đè do đó nó không hiển thị trong lớp RecylerView theo mặc định, điều này khiến nhiều nhà phát triển (bao gồm cả tôi) tự hỏi nên bắt đầu từ đâu. Một khi bạn biết rằng phương pháp này tồn tại, việc tạo RecyclerView như vậy sẽ là một lối đi lại.

Hãy xem một ví dụ để chứng minh quan điểm của tôi. Nếu bạn muốn hiển thị hai bố cục ở các vị trí thay thế, hãy làm điều này

@Override
public int getItemViewType(int position)
{
   if(position%2==0)       // Even position 
     return LAYOUT_ONE;
   else                   // Odd position 
     return LAYOUT_TWO;
}

Liên kết có liên quan:

Kiểm tra dự án nơi tôi đã thực hiện điều này


15

Vâng, nó là có thể. Trong bộ điều hợp của bạn getItemViewType Bố cục như thế này ....

  public class MultiViewTypeAdapter extends RecyclerView.Adapter {

        private ArrayList<Model>dataSet;
        Context mContext;
        int total_types;
        MediaPlayer mPlayer;
        private boolean fabStateVolume = false;

        public static class TextTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            CardView cardView;

            public TextTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.cardView = (CardView) itemView.findViewById(R.id.card_view);
            }
        }

        public static class ImageTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            ImageView image;

            public ImageTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.image = (ImageView) itemView.findViewById(R.id.background);
            }
        }

        public static class AudioTypeViewHolder extends RecyclerView.ViewHolder {

            TextView txtType;
            FloatingActionButton fab;

            public AudioTypeViewHolder(View itemView) {
                super(itemView);

                this.txtType = (TextView) itemView.findViewById(R.id.type);
                this.fab = (FloatingActionButton) itemView.findViewById(R.id.fab);
            }
        }

        public MultiViewTypeAdapter(ArrayList<Model>data, Context context) {
            this.dataSet = data;
            this.mContext = context;
            total_types = dataSet.size();
        }

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

            View view;
            switch (viewType) {
                case Model.TEXT_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_type, parent, false);
                    return new TextTypeViewHolder(view);
                case Model.IMAGE_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_type, parent, false);
                    return new ImageTypeViewHolder(view);
                case Model.AUDIO_TYPE:
                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.audio_type, parent, false);
                    return new AudioTypeViewHolder(view);
            }
            return null;
        }

        @Override
        public int getItemViewType(int position) {

            switch (dataSet.get(position).type) {
                case 0:
                    return Model.TEXT_TYPE;
                case 1:
                    return Model.IMAGE_TYPE;
                case 2:
                    return Model.AUDIO_TYPE;
                default:
                    return -1;
            }
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int listPosition) {

            Model object = dataSet.get(listPosition);
            if (object != null) {
                switch (object.type) {
                    case Model.TEXT_TYPE:
                        ((TextTypeViewHolder) holder).txtType.setText(object.text);

                        break;
                    case Model.IMAGE_TYPE:
                        ((ImageTypeViewHolder) holder).txtType.setText(object.text);
                        ((ImageTypeViewHolder) holder).image.setImageResource(object.data);
                        break;
                    case Model.AUDIO_TYPE:

                        ((AudioTypeViewHolder) holder).txtType.setText(object.text);

                }
            }
        }

        @Override
        public int getItemCount() {
            return dataSet.size();
        }
    }

cho liên kết tham khảo: https://www.journaldev.com/12372/android-recyclerview-example


Tôi đã định dạng lại mã của mình để bắt chước đoạn mã này và bây giờ nó hoạt động hoàn hảo. Vấn đề tôi gặp phải là khi vuốt ngoài trang hiện tại nó sẽ bị sập. Tai nạn không còn nữa! Mô hình xuất sắc ,. Cảm ơn bạn . Làm tốt.
dùng462990

Không thể tìm thấy bất cứ điều gì hữu ích trong nhiều ngày cho đến khi tôi nhìn thấy cái này, Cảm ơn bạn!
Itay Braha

7

theo giải pháp của Anton, hãy đưa ra giải pháp này ViewHolderchứa / xử lý / ủy nhiệm các loại bố cục khác nhau. Nhưng không chắc cách bố trí thay thế mới có hoạt động khi chế độ xem tái chế khôngViewHolder không phải là loại cuộn dữ liệu.

Nên về cơ bản, onCreateViewHolder(ViewGroup parent, int viewType) chỉ được gọi khi cần bố trí chế độ xem mới;

getItemViewType(int position) sẽ được gọi cho viewType ;

onBindViewHolder(ViewHolder holder, int position) luôn được gọi khi tái chế chế độ xem (dữ liệu mới được đưa vào và cố gắng hiển thị với chế độ xem đó ViewHolder ).

Vì vậy, khi onBindViewHolderđược gọi, nó cần đặt trong bố cục xem đúng và cập nhậtViewHolder .

Là cách chính xác để thay thế bố cục khung nhìn cho điều đó ViewHoldersẽ được đưa vào, hoặc bất kỳ vấn đề? Đánh giá cao bất kỳ bình luận!

public int getItemViewType(int position) {
    TypedData data = mDataSource.get(position);
    return data.type;
}

public ViewHolder onCreateViewHolder(ViewGroup parent, 
    int viewType) {
    return ViewHolder.makeViewHolder(parent, viewType);
}

public void onBindViewHolder(ViewHolder holder, 
    int position) {
    TypedData data = mDataSource.get(position);
    holder.updateData(data);
}

///
public static class ViewHolder extends 
    RecyclerView.ViewHolder {

    ViewGroup mParentViewGroup;
    View mCurrentViewThisViewHolderIsFor;
    int mDataType;

    public TypeOneViewHolder mTypeOneViewHolder;
    public TypeTwoViewHolder mTypeTwoViewHolder;

    static ViewHolder makeViewHolder(ViewGroup vwGrp, 
        int dataType) {
        View v = getLayoutView(vwGrp, dataType);
        return new ViewHolder(vwGrp, v, viewType);
    }

    static View getLayoutView(ViewGroup vwGrp, 
        int dataType) {
        int layoutId = getLayoutId(dataType);
        return LayoutInflater.from(vwGrp.getContext())
                             .inflate(layoutId, null);
    }

    static int getLayoutId(int dataType) {
        if (dataType == TYPE_ONE) {
            return R.layout.type_one_layout;
        } else if (dataType == TYPE_TWO) {
            return R.layout.type_two_layout;
        }
    }

    public ViewHolder(ViewGroup vwGrp, View v, 
        int dataType) {
        super(v);
        mDataType = dataType;
        mParentViewGroup = vwGrp;
        mCurrentViewThisViewHolderIsFor = v;

        if (data.type == TYPE_ONE) {
            mTypeOneViewHolder = new TypeOneViewHolder(v);
        } else if (data.type == TYPE_TWO) {
            mTypeTwoViewHolder = new TypeTwoViewHolder(v);
        }
    }

    public void updateData(TypeData data) {
        mDataType = data.type;
        if (data.type == TYPE_ONE) {
            mTypeTwoViewHolder = null;
            if (mTypeOneViewHolder == null) {
                View newView = getLayoutView(mParentViewGroup,
                               data.type);

                /**
                 *  how to replace new view with 
                    the view in the parent 
                    view container ???
                 */
                replaceView(mCurrentViewThisViewHolderIsFor, 
                            newView);
                mCurrentViewThisViewHolderIsFor = newView;

                mTypeOneViewHolder = 
                    new TypeOneViewHolder(newView);
            }
            mTypeOneViewHolder.updateDataTypeOne(data);

        } else if (data.type == TYPE_TWO){
            mTypeOneViewHolder = null;
            if (mTypeTwoViewHolder == null) {
                View newView = getLayoutView(mParentViewGroup, 
                               data.type);

                /**
                 *  how to replace new view with 
                    the view in the parent view 
                    container ???
                 */
                replaceView(mCurrentViewThisViewHolderIsFor, 
                            newView);
                mCurrentViewThisViewHolderIsFor = newView;

                mTypeTwoViewHolder = 
                    new TypeTwoViewHolder(newView);
            }
            mTypeTwoViewHolder.updateDataTypeOne(data);
        }
    }
}

public static void replaceView(View currentView, 
    View newView) {
    ViewGroup parent = (ViewGroup)currentView.getParent();
    if(parent == null) {
        return;
    }
    final int index = parent.indexOfChild(currentView);
    parent.removeView(currentView);
    parent.addView(newView, index);
}

Biên tập: ViewHolder có thành viên mItemViewType để giữ chế độ xem

Biên tập: trông giống như trong onBindViewHolder (người giữ ViewHolder, vị trí int) mà ViewHolder được truyền vào đã được chọn (hoặc tạo) bằng cách xem getItemViewType (vị trí int) để đảm bảo rằng đó là một trận đấu, vì vậy có thể không cần phải lo lắng về điều đó của ViewHolder loại không khớp với loại dữ liệu [vị trí]. Có ai biết thêm về cách ViewHolder trong onBindViewHolder () được chọn không?

Chỉnh sửa: Có vẻ như Tái chế ViewHolderđược chọn theo loại, vì vậy không có chiến binh nào ở đó.

Chỉnh sửa: http://wiresareobsolete.com/2014/09/building-a-recyclerview-layoutmanager-part-1/ trả lời câu hỏi này.

Nó được tái chế ViewHoldernhư:

holder = getRecycledViewPool().getRecycledView(mAdapter.getItemViewType(offsetPosition));

hoặc tạo cái mới nếu không tìm thấy tái chế ViewHolderđúng loại.

public ViewHolder getRecycledView(int viewType) {
        final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
        if (scrapHeap != null && !scrapHeap.isEmpty()) {
            final int index = scrapHeap.size() - 1;
            final ViewHolder scrap = scrapHeap.get(index);
            scrapHeap.remove(index);
            return scrap;
        }
        return null;
    }

View getViewForPosition(int position, boolean dryRun) {
    ......

    if (holder == null) {
            final int offsetPosition = mAdapterHelper.findPositionOffset(position);
            if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
                        + "position " + position + "(offset:" + offsetPosition + ")."
                        + "state:" + mState.getItemCount());
            }

            final int type = mAdapter.getItemViewType(offsetPosition);
            // 2) Find from scrap via stable ids, if exists
            if (mAdapter.hasStableIds()) {
                holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
                if (holder != null) {
                    // update position
                    holder.mPosition = offsetPosition;
                    fromScrap = true;
                }
            }
            if (holder == null && mViewCacheExtension != null) {
                // We are NOT sending the offsetPosition because LayoutManager does not
                // know it.
                final View view = mViewCacheExtension
                        .getViewForPositionAndType(this, position, type);
                if (view != null) {
                    holder = getChildViewHolder(view);
                    if (holder == null) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned"
                                + " a view which does not have a ViewHolder");
                    } else if (holder.shouldIgnore()) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned"
                                + " a view that is ignored. You must call stopIgnoring before"
                                + " returning this view.");
                    }
                }
            }
            if (holder == null) { // fallback to recycler
                // try recycler.
                // Head to the shared pool.
                if (DEBUG) {
                    Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared "
                            + "pool");
                }
                holder = getRecycledViewPool()
                        .getRecycledView(mAdapter.getItemViewType(offsetPosition));
                if (holder != null) {
                    holder.resetInternal();
                    if (FORCE_INVALIDATE_DISPLAY_LIST) {
                        invalidateDisplayListInt(holder);
                    }
                }
            }
            if (holder == null) {
                holder = mAdapter.createViewHolder(RecyclerView.this,
                        mAdapter.getItemViewType(offsetPosition));
                if (DEBUG) {
                    Log.d(TAG, "getViewForPosition created new ViewHolder");
                }
            }
        }
        boolean bound = false;
        if (mState.isPreLayout() && holder.isBound()) {
            // do not update unless we absolutely have to.
            holder.mPreLayoutPosition = position;
        } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
            if (DEBUG && holder.isRemoved()) {
                throw new IllegalStateException("Removed holder should be bound and it should"
                        + " come here only in pre-layout. Holder: " + holder);
            }
            final int offsetPosition = mAdapterHelper.findPositionOffset(position);
            mAdapter.bindViewHolder(holder, offsetPosition);
            attachAccessibilityDelegate(holder.itemView);
            bound = true;
            if (mState.isPreLayout()) {
                holder.mPreLayoutPosition = position;
            }
        }

        final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        final LayoutParams rvLayoutParams;
        if (lp == null) {
            rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
            holder.itemView.setLayoutParams(rvLayoutParams);
        } else if (!checkLayoutParams(lp)) {
            rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
            holder.itemView.setLayoutParams(rvLayoutParams);
        } else {
            rvLayoutParams = (LayoutParams) lp;
        }
        rvLayoutParams.mViewHolder = holder;
        rvLayoutParams.mPendingInvalidate = fromScrap && bound;
        return holder.itemView;
}

6

Tôi có một giải pháp tốt hơn cho phép tạo nhiều kiểu xem theo cách khai báo và kiểu an toàn. Nó được viết bằng Kotlin mà btw thực sự rất hay.

Chủ sở hữu chế độ xem đơn giản cho tất cả các loại chế độ xem được yêu cầu

class ViewHolderMedium(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val icon: ImageView = itemView.findViewById(R.id.icon) as ImageView
    val label: TextView = itemView.findViewById(R.id.label) as TextView
}

Có một sự trừu tượng của mục dữ liệu bộ điều hợp. Lưu ý rằng loại chế độ xem được biểu thị bằng mã băm của lớp chủ sở hữu chế độ xem cụ thể (KClass trong Kotlin)

trait AdapterItem {
   val viewType: Int
   fun bindViewHolder(viewHolder: RecyclerView.ViewHolder)
}

abstract class AdapterItemBase<T>(val viewHolderClass: KClass<T>) : AdapterItem {
   override val viewType: Int = viewHolderClass.hashCode()  
   abstract fun bindViewHolder(viewHolder: T)
   override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
       bindViewHolder(viewHolder as T)
   }
}

Chỉ bindViewHoldercần được ghi đè trong các lớp mục bộ điều hợp cụ thể (loại cách an toàn)

class AdapterItemMedium(val icon: Drawable, val label: String, val onClick: () -> Unit) : AdapterItemBase<ViewHolderMedium>(ViewHolderMedium::class) {
    override fun bindViewHolder(viewHolder: ViewHolderMedium) {
        viewHolder.icon.setImageDrawable(icon)
        viewHolder.label.setText(label)
        viewHolder.itemView.setOnClickListener { onClick() }
    }
}

Danh sách các AdapterItemMediumđối tượng như vậy là một nguồn dữ liệu cho bộ điều hợp thực sự chấp nhận List<AdapterItem>xem bên dưới.

Phần quan trọng của giải pháp này là một nhà máy giữ khung nhìn sẽ cung cấp các phiên bản mới của một ViewHolder cụ thể

class ViewHolderProvider {
    private val viewHolderFactories = hashMapOf<Int, Pair<Int, Any>>()

    fun provideViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val (layoutId: Int, f: Any) = viewHolderFactories.get(viewType)
        val viewHolderFactory = f as (View) -> RecyclerView.ViewHolder
        val view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutId, viewGroup, false)
        return viewHolderFactory(view)
    }

    fun registerViewHolderFactory<T>(key: KClass<T>, layoutId: Int, viewHolderFactory: (View) -> T) {
        viewHolderFactories.put(key.hashCode(), Pair(layoutId, viewHolderFactory))
    }
}

Và lớp bộ điều hợp đơn giản trông như thế này

public class MultitypeAdapter(val items: List<AdapterItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

   val viewHolderProvider = ViewHolderProvider() // inject ex Dagger2

   init {
        viewHolderProvider!!.registerViewHolderFactory(ViewHolderMedium::class, R.layout.item_medium, { itemView ->
            ViewHolderMedium(itemView)
        })
   }

   override fun getItemViewType(position: Int): Int {
        return items[position].viewType
    }

    override fun getItemCount(): Int {
        return items.size()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
        return viewHolderProvider!!.provideViewHolder(viewGroup, viewType)
    }

    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
        items[position].bindViewHolder(viewHolder)     
    }
}

Chỉ có 3 bước để tạo kiểu xem mới:

  1. tạo một lớp giữ khung nhìn
  2. tạo một lớp mục bộ điều hợp (mở rộng từ AdapterItemBase)
  3. đăng ký lớp người giữ trong ViewHolderProvider

Dưới đây là một ví dụ về khái niệm này: android-ngăn kéo-mẫu Nó còn đi xa hơn - kiểu xem hoạt động như một thành phần spinner, các mục bộ điều hợp có thể lựa chọn.


6

Nó rất đơn giản và thẳng về phía trước.

Chỉ cần ghi đè phương thức getItemViewType () trong bộ điều hợp của bạn. Trên cơ sở dữ liệu trả về các giá trị itemViewType khác nhau. ví dụ: Hãy xem xét một đối tượng thuộc kiểu Person có thành viên isMale, nếu isMale là true, return 1 và isMale là false, return 2 trong getItemViewType () phương thức .

Bây giờ đến với createdViewHolder (cha mẹ của Viewgroup, int viewType) , trên cơ sở các viewType yon khác nhau có thể làm tăng các tệp bố cục khác nhau. như sau

 if (viewType ==1){
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.male,parent,false);
    return new AdapterMaleViewHolder(view);
}
else{
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.female,parent,false);
    return new AdapterFemaleViewHolder(view);
}

trong onBindViewHolder (chủ sở hữu VH, vị trí int) kiểm tra nơi chủ sở hữu là thể hiện của AdapterFemaleViewHolderhoặc AdapterMaleViewHolderbằng cách instanceofgán giá trị.

ViewHolder có thể như thế này

    class AdapterMaleViewHolder extends RecyclerView.ViewHolder {
            ...
            public AdapterMaleViewHolder(View itemView){
            ...
            }
        }

    class AdapterFemaleViewHolder extends RecyclerView.ViewHolder {
         ...
         public AdapterFemaleViewHolder(View itemView){
            ...
         }
    }

4

Mặc dù câu trả lời được chọn là chính xác, tôi chỉ muốn giải thích thêm. Tôi tìm thấy ở đây một Bộ điều hợp tùy chỉnh hữu ích cho nhiều kiểu xem trong RecyclerView . Phiên bản Kotlin của nó là đây .

Bộ điều hợp tùy chỉnh đang theo sau

public class CustomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
ArrayList<String> list; // ArrayList of your Data Model
final int VIEW_TYPE_ONE = 1;
final int VIEW_TYPE_TWO = 2;

public CustomAdapter(Context context, ArrayList<String> list) { // you can pass other parameters in constructor
    this.context = context;
    this.list = list;
}

private class ViewHolder1 extends RecyclerView.ViewHolder {

    TextView yourView;
    ViewHolder1(final View itemView) {
        super(itemView);
        yourView = itemView.findViewById(R.id.yourView); // Initialize your All views prensent in list items
    }
    void bind(int position) {
        // This method will be called anytime a list item is created or update its data
        //Do your stuff here
        yourView.setText(list.get(position));
    }
}

private class ViewHolder2 extends RecyclerView.ViewHolder {

    TextView yourView;
    ViewHolder2(final View itemView) {
        super(itemView);
        yourView = itemView.findViewById(R.id.yourView); // Initialize your All views prensent in list items
    }
    void bind(int position) {
        // This method will be called anytime a list item is created or update its data
        //Do your stuff here
        yourView.setText(list.get(position));
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
   if (viewType == VIEW_TYPE_ONE) {
       return new ViewHolder1(LayoutInflater.from(context).inflate(R.layout.your_list_item_1, parent, false));
   }
   //if its not VIEW_TYPE_ONE then its VIEW_TYPE_TWO
   return new ViewHolder2(LayoutInflater.from(context).inflate(R.layout.your_list_item_2, parent, false));

}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (list.get(position).type == Something) { // put your condition, according to your requirements
        ((ViewHolder1) holder).bind(position);
    } else {
        ((ViewHolder2) holder).bind(position);
    }

}

@Override
public int getItemCount() {
    return list.size();
}

@Override
public int getItemViewType(int position) {
    // here you can get decide from your model's ArrayList, which type of view you need to load. Like
    if (list.get(position).type == Something) { // put your condition, according to your requirements
        return VIEW_TYPE_ONE;
    }
    return VIEW_TYPE_TWO;
}
}

3

Tôi đề nghị thư viện này từ Hannes Dorfmann. Nó gói gọn tất cả logic liên quan đến kiểu xem cụ thể trong một đối tượng riêng biệt gọi là "AdapterDelegate". https://github.com/sockeqwe/AdOGDelegates

public class CatAdapterDelegate extends AdapterDelegate<List<Animal>> {

  private LayoutInflater inflater;

  public CatAdapterDelegate(Activity activity) {
    inflater = activity.getLayoutInflater();
  }

  @Override public boolean isForViewType(@NonNull List<Animal> items, int position) {
    return items.get(position) instanceof Cat;
  }

  @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
    return new CatViewHolder(inflater.inflate(R.layout.item_cat, parent, false));
  }

  @Override public void onBindViewHolder(@NonNull List<Animal> items, int position,
      @NonNull RecyclerView.ViewHolder holder, @Nullable List<Object> payloads) {

    CatViewHolder vh = (CatViewHolder) holder;
    Cat cat = (Cat) items.get(position);

    vh.name.setText(cat.getName());
  }

  static class CatViewHolder extends RecyclerView.ViewHolder {

    public TextView name;

    public CatViewHolder(View itemView) {
      super(itemView);
      name = (TextView) itemView.findViewById(R.id.name);
    }
  }
}

public class AnimalAdapter extends ListDelegationAdapter<List<Animal>> {

  public AnimalAdapter(Activity activity, List<Animal> items) {

    // DelegatesManager is a protected Field in ListDelegationAdapter
    delegatesManager.addDelegate(new CatAdapterDelegate(activity))
                    .addDelegate(new DogAdapterDelegate(activity))
                    .addDelegate(new GeckoAdapterDelegate(activity))
                    .addDelegate(23, new SnakeAdapterDelegate(activity));

    // Set the items from super class.
    setItems(items);
  }
}

1

Thật ra, tôi muốn cải thiện câu trả lời của Anton .

getItemViewType(int position)trả về một giá trị số nguyên, bạn có thể trả về ID tài nguyên bố cục mà bạn cần tăng. Bằng cách đó, bạn sẽ lưu một số logic trongonCreateViewHolder(ViewGroup parent, int viewType) phương pháp.

Ngoài ra, tôi sẽ không đề xuất thực hiện các tính toán chuyên sâu getItemCount()vì chức năng cụ thể đó được gọi ít nhất 5 lần trong khi hiển thị danh sách, cũng như trong khi hiển thị từng mục ngoài các mục hiển thị. Đáng buồn thay vì notifyDatasetChanged()phương thức là cuối cùng, bạn thực sự không thể ghi đè lên nó, nhưng bạn có thể gọi nó từ một chức năng khác trong bộ điều hợp.


3
Vâng, điều đó có thể hoạt động, nhưng sẽ gây nhầm lẫn cho các nhà phát triển khác. Ngoài ra từ Tài liệu Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.Vì vậy, tốt hơn hết là viết thêm một chút mã và không sử dụng hack.
Ioane Sharvadze

1
Tôi đồng ý. Hồi đó tôi đã bỏ lỡ điều khoản cụ thể đó.
Dragas

Điều đó thật buồn cười vì các tài liệu RecyclerView.Ad CHƯƠNG: getItemViewType () ở đây developer.android.com/reference/android/support/v7/widget/ gợi ý những gì Dragas đã đăng mà bạn nên "Cân nhắc sử dụng tài nguyên id để xác định duy nhất các loại chế độ xem mục. " dường như không biết gì về yêu cầu cho getViewTypeCount ()
Deemoe

1

Bạn có thể sử dụng thư viện: https://github.com/vivchar/RendererRecyclerViewAdOG

mRecyclerViewAdapter = new RendererRecyclerViewAdapter(); /* included from library */
mRecyclerViewAdapter.registerRenderer(new SomeViewRenderer(SomeModel.TYPE, this));
mRecyclerViewAdapter.registerRenderer(...); /* you can use several types of cells */

`

Đối với mỗi mục, bạn nên triển khai ViewRenderer, ViewHolder, someModel:

ViewHolder - nó là một khung nhìn đơn giản của khung nhìn tái chế.

Một số mô hình - đó là mô hình của bạn với ItemModelgiao diện

public class SomeViewRenderer extends ViewRenderer<SomeModel, SomeViewHolder> {

  public SomeViewRenderer(final int type, final Context context) {
    super(type, context);
  }
  @Override
 public void bindView(@NonNull final SomeModel model, @NonNull final SomeViewHolder holder) {
    holder.mTitle.setText(model.getTitle());
 }
 @NonNull
 @Override
 public SomeViewHolder createViewHolder(@Nullable final ViewGroup parent) {
    return new SomeViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.some_item, parent, false));
 }
}

Để biết thêm chi tiết bạn có thể xem tài liệu.


1

Xem các kiểu triển khai trở nên dễ dàng hơn với kotlin, đây là một mẫu với thư viện ánh sáng này https://github.com/Link184/KidAd CHƯƠNG

recyclerView.setUp {
    withViewType {
        withLayoutResId(R.layout.item_int)
        withItems(mutableListOf(1, 2, 3, 4, 5, 6))
        bind<Int> { // this - is adapter view hoder itemView, it - current item
            intName.text = it.toString()
        }
    }


    withViewType("SECOND_STRING_TAG") {
        withLayoutResId(R.layout.item_text)
        withItems(mutableListOf("eight", "nine", "ten", "eleven", "twelve"))
        bind<String> {
            stringName.text = it
        }
    }
}

1

Bạn có thể giao dịch nhiềuViewTypes RecyclerAdapterbằng cách getItemViewType()trả về dự kiếnviewType giá trị cho vị trí đó

Tôi đã chuẩn bị một MultipleViewTypeAdapterdanh sách MCQ để xây dựng các bài kiểm tra có thể đưa ra một câu hỏi có thể có 2 câu trả lời hợp lệ trở lên (tùy chọn hộp kiểm) và một câu hỏi trả lời duy nhất (tùy chọn radiobutton).

Đối với điều này, tôi nhận được loại Câu hỏi từ phản hồi API và tôi đã sử dụng nó để quyết định chế độ xem nào tôi phải hiển thị cho câu hỏi đó.

public class MultiViewTypeAdapter extends RecyclerView.Adapter {

    Context mContext;
    ArrayList<Question> dataSet;
    ArrayList<String> questions;
    private Object radiobuttontype1; 


    //Viewholder to display Questions with checkboxes
    public static class Checkboxtype2 extends RecyclerView.ViewHolder {
        ImageView imgclockcheck;
        CheckBox checkbox;

        public Checkboxtype2(@NonNull View itemView) {
            super(itemView);
            imgclockcheck = (ImageView) itemView.findViewById(R.id.clockout_cbox_image);
            checkbox = (CheckBox) itemView.findViewById(R.id.clockout_cbox);


        }
    }

        //Viewholder to display Questions with radiobuttons

    public static class Radiobuttontype1 extends RecyclerView.ViewHolder {
        ImageView clockout_imageradiobutton;
        RadioButton clockout_radiobutton;
        TextView sample;

        public radiobuttontype1(View itemView) {
            super(itemView);
            clockout_imageradiobutton = (ImageView) itemView.findViewById(R.id.clockout_imageradiobutton);
            clockout_radiobutton = (RadioButton) itemView.findViewById(R.id.clockout_radiobutton);
            sample = (TextView) itemView.findViewById(R.id.sample);
        }
    }

    public MultiViewTypeAdapter(ArrayList<QueDatum> data, Context context) {
        this.dataSet = data;
        this.mContext = context;

    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {

        if (viewType.equalsIgnoreCase("1")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("2")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_cbox_list_row, viewGroup, false);
            view.setHorizontalFadingEdgeEnabled(true);
            return new Checkboxtype2(view);

        } else if (viewType.equalsIgnoreCase("3")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("4")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("5")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);
        }


        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int viewType) {
        if (viewType.equalsIgnoreCase("1")) {
            options =  dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            ((radiobuttontype1) viewHolder).clockout_radiobutton.setChecked(false);
            ((radiobuttontype1) viewHolder).sample.setText(question);
            //loading image bitmap in the ViewHolder's View
            Picasso.with(mContext)
                    .load(image)
                    .into(((radiobuttontype1) viewHolder).clockout_imageradiobutton);

        } else if (viewType.equalsIgnoreCase("2")) {
            options = (ArrayList<Clockout_questions_Option>) dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            //loading image bitmap in the ViewHolder's View
            Picasso.with(mContext)
                    .load(image)
                    .into(((Checkboxtype2) viewHolder).imgclockcheck);

        } else if (viewType.equalsIgnoreCase("3")) {
                //fit data to viewHolder for ViewType 3
        } else if (viewType.equalsIgnoreCase("4")) {
//fit data to viewHolder for ViewType 4   
        } else if (viewType.equalsIgnoreCase("5")) {
//fit data to viewHolder for ViewType 5     
        }
    }

    @Override
    public int getItemCount() {
        return dataSet.size();
    }

    /**
     * returns viewType for that position by picking the viewType value from the 
     *     dataset
     */
    @Override
    public int getItemViewType(int position) {
        return dataSet.get(position).getViewType();

    }


}

Bạn có thể tránh được nhiều lần điền dữ liệu của viewHolder dựa trên điều kiện onBindViewHolder()bằng cách gán cùng một id cho các chế độ xem tương tự trên các viewHolders khác nhau về vị trí của chúng.


0

Nếu bạn muốn sử dụng nó cùng với Liên kết dữ liệu Android, hãy xem https://github.com/evant/binding-collection-ad CHƯƠNG - đó là giải pháp tốt nhất cho nhiều loại chế độ xemRecyclerView tôi từng thấy.

bạn có thể sử dụng nó như

var items: AsyncDiffPagedObservableList<BaseListItem> =
        AsyncDiffPagedObservableList(GenericDiff)

    val onItemBind: OnItemBind<BaseListItem> =
        OnItemBind { itemBinding, _, item -> itemBinding.set(BR.item, item.layoutRes) }

và sau đó trong bố trí nơi danh sách

 <androidx.recyclerview.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                app:enableAnimations="@{false}"
                app:scrollToPosition="@{viewModel.scrollPosition}"

                app:itemBinding="@{viewModel.onItemBind}"
                app:items="@{viewModel.items}"

                app:reverseLayoutManager="@{true}"/>

mục danh sách của bạn phải thực hiện BaseListItemgiao diện trông như thế này

interface BaseListItem {
    val layoutRes: Int
}

và chế độ xem mục sẽ trông giống như thế này

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
                name="item"
                type="...presentation.somescreen.list.YourListItem"/>
    </data>

   ...

</layout>

Nơi YourListItemthực hiệnBaseListItem

Hy vọng nó sẽ giúp được ai đó.


0

đầu tiên bạn phải tạo 2 bố cục xml. sau đó bên trong bộ chuyển đổi recyclerview TYPE_CALL và TYPE_EMAIL là hai giá trị tĩnh với 1 và 2 tương ứng trong lớp bộ điều hợp.

bây giờ Xác định hai giá trị tĩnh ở cấp độ lớp Recycler xem ví dụ: private static int TYPE_CALL = 1; int tĩnh int TYPE_EMAIL = 2;

Bây giờ tạo chủ sở hữu chế độ xem với nhiều chế độ xem như thế này:

class CallViewHolder extends RecyclerView.ViewHolder {

    private TextView txtName;
    private TextView txtAddress;

    CallViewHolder(@NonNull View itemView) {
        super(itemView);
        txtName = itemView.findViewById(R.id.txtName);
        txtAddress = itemView.findViewById(R.id.txtAddress);
    }
}
class EmailViewHolder extends RecyclerView.ViewHolder {

    private TextView txtName;
    private TextView txtAddress;

    EmailViewHolder(@NonNull View itemView) {
        super(itemView);
        txtName = itemView.findViewById(R.id.txtName);
        txtAddress = itemView.findViewById(R.id.txtAddress);
    }
}

Bây giờ mã như dưới đây trong phương thức onCreateViewHolder và onBindViewHolder trong bộ điều hợp recyclerview:

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
    View view;
    if (viewType == TYPE_CALL) { // for call layout
        view = LayoutInflater.from(context).inflate(R.layout.item_call, viewGroup, false);
        return new CallViewHolder(view);

    } else { // for email layout
        view = LayoutInflater.from(context).inflate(R.layout.item_email, viewGroup, false);
        return new EmailViewHolder(view);
    }
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
    if (getItemViewType(position) == TYPE_CALL) {
        ((CallViewHolder) viewHolder).setCallDetails(employees.get(position));
    } else {
        ((EmailViewHolder) viewHolder).setEmailDetails(employees.get(position));
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.