Birden çok görünüm türüyle RecyclerView nasıl oluşturulur?


864

Gönderen https://developer.android.com/preview/material/ui-widgets.html

Biz oluşturduğunuzda RecyclerView.Adapterbiz belirtmek zorunda ViewHolderadaptör ile Will'di bağlama.

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;
    }
}

Peki, RecyclerViewbirden çok görünüm türüyle oluşturmak mümkün mü?


5
Anton'un cevabının üstüne, cevabımı buraya bakın: stackoverflow.com/questions/25914003/…
ticofab

Sizin için de yararlı olabilecek bu bağlantıyı kontrol edin stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

1
İyi öğretici burada: guides.codepath.com/android/…
Gene Bo

Bu bağlantıyı kontrol edin uygulanabilir olduğunu stackoverflow.com/questions/39971350/… Lütfen bana bildirin daha fazla sorun varsa
Ravindra Kushwaha

Uygulamak için büyük kütüphane github.com/vivchar/RendererRecyclerViewAdapter
Vitaly

Yanıtlar:


1269

Evet mümkün. Sadece getItemViewType () yöntemini uygulayın ve içindeki viewTypeparametreye dikkat edin onCreateViewHolder().

Yani şöyle bir şey yaparsınız:

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
Bu benim noktam çünkü bir RecyclerView.Adapter sadece tek bir ViewHolder kullanılabilir nasıl birden çok eklemek için?
Pongpat

48
Sonra genel tür amacını yenmek düşünüyorum onBindViewHolder () yönteminde viewholder türü döküm gerekir. Bu arada, cevabınız için teşekkür ederim.
Pongpat

32
Bir BaseHolder oluşturabilir ve gerekli tüm türler için genişletebilirsiniz. Sonra uygulama sahiplerinde geçersiz kılınacak (overrode?) Soyut bir setData ekleyin. Bu şekilde dilin tür farklılıklarını işlemesine izin verirsiniz. Ancak, yalnızca tüm liste öğelerinin yorumlayabileceği tek bir veri kümeniz varsa çalışır.
DariusL

2
Farklı düzen dosyası ne olacak? Düzeni değiştirmek istiyorum optionMenuItem. Nasıl mümkün olabilir? @AntonSavin
Pratik Butani

5
ViewHolders'ınız RecyclerView Adaptörünüzde bulunuyorsa statik olmalıdır
Samer

88

Görünüm türleri için düzenler çok azsa ve bağlayıcı mantıklar basitse, Anton'un çözümünü izleyin.
Ancak karmaşık düzenleri ve bağlayıcı mantıkları yönetmeniz gerekiyorsa kod dağınık olacaktır.

Aşağıdaki çözümün karmaşık görünüm türlerini ele alması gereken biri için yararlı olacağına inanıyorum.

Temel DataBinder sınıfı

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();

......

}

Bu sınıfta tanımlamak için gereken işlevler, tek görünüm türü oluşturulurken bağdaştırıcı sınıfıyla hemen hemen aynıdır.
Her görünüm türü için, bu DataBinder öğesini genişleterek sınıfı oluşturun.

Örnek DataBinder sınıfı

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);
        }
    }
}

DataBinder sınıflarını yönetmek için adaptör sınıfı oluşturun.

Base DataBindAdapter sınıfı

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);

......

}

Bu temel sınıfı genişleterek sınıfı oluşturun ve sonra DataBinder sınıflarını başlatın ve soyut yöntemleri geçersiz kılın

  1. getItemCount
    DataBinder öğelerinin toplam öğe sayısını döndürür

  2. getItemViewType
    Bağdaştırıcı konumu ve görünüm türü arasındaki eşleme mantığını tanımlayın.

  3. getDataBinder
    DataBinder örneğini görünüm türüne göre döndürür

  4. getPosition
    Belirtilen DataBinder'daki konumdan adaptör konumuna dönüştürme mantığını tanımlayın

  5. getBinderPosition
    Adaptör konumundan DataBinder içindeki konuma mantık dönüştürme tanımlayın

Umarım bu çözüm yardımcı olacaktır.
GitHub'da daha ayrıntılı çözüm ve örnekler bıraktım, bu yüzden lütfen gerekirse aşağıdaki bağlantıya bakın.
https://github.com/yqritc/RecyclerView-MultipleViewTypesAdapter


4
Kodunuzla biraz kafam karıştı, belki bana yardımcı olabilirsiniz, görüşlerimin listedeki konumlarla değil, bakış açılarıyla tanımlanmasını isterim. Kodunuzdaki görünümler konumlarına göre belirlenmiş gibi görünür. böylece konum 1'de im, görünüm 1 görüntülenir, konum 3, görünüm 3 görüntülenir ve diğer her şey konum 2'nin görünümünü görüntüler. Görünümlerimi konumlara değil, görünüm türlerine dayandırmak istiyorum - bu yüzden görünüm türünün görüntüler olduğunu belirtirseniz, görüntüyü görüntülemelidir. Bunu nasıl yapabilirim?
Simon

Maalesef, sorunuzu tam olarak anlayamadım ..., ancak konumu ve görüş türünü bağlamak için mantığı bir yere yazmanız gerekiyor.
yqritc

1
bu kod karışık değildir, bu bir RecyclerView Adapter kalıbıdır ve bu sorunun doğru cevabı gibi kabul edilmelidir. @ Yqritc bağlantısını takip edin, keşfedilmek için biraz zaman ayırın ve farklı düzen düzenleriyle RecyclerView için mükemmel bir desene sahip olacaksınız.
Stoycho Andreev

Yeni burada, public class DataBinder<T extends RecyclerView.ViewHolder>biri bana ne <T someClass>denir söyleyebilir , bu yüzden terim alırsam google yapabilirsiniz. Ayrıca abstract public class DataBinder<T extends RecyclerView.ViewHolder>dediğimde bu, bu sınıfın türü olduğu anlamına mı geliyor, ViewHoldersonuç olarak bu sınıfı genişleten her sınıfın türü bu olacak viewHoldermı?
rgv

1
@cesards beni tekrar polimorfizm lol bilgimi yenilemek için yaptı .... Java fena değil
Paul Okeke

37

Aşağıdaki sahte kod değil ve ben test ettim ve benim için çalıştı.

Geri dönüşüm görünümümde bir ana başlık oluşturmak ve ardından kullanıcının tıklayabileceği başlığın altında bir resim listesi görüntülemek istedim.

Kodumda birkaç anahtar kullandım, bunu yapmanın en etkili yolu olup olmadığını bilmiyorum, bu yüzden yorumlarınızı vermekten çekinmeyin:

   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));
            }

        }
    }

Bu güzel, dinamik konumlarda birden fazla başlık istersem ne olur? Diyelim ki, kategorileri tanımlayan başlıkları olan öğelerin listesi. Çözümünüz, özel başlıkların önceden belirlenmiş int konumlarında olmasını gerektiriyor gibi görünüyor.
Bassinator

22

Evet mümkün.

Genel bir görünüm tutucu yazın:

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

    public abstract  void setDataOnView(int position);
}

daha sonra görünüm tutucularınızı oluşturun ve GenericViewHolder'ı genişletmelerini sağlayın. Örneğin, bu:

     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);
        }
    }
}

sonra RecyclerView.Adapter sınıfı aşağıdaki gibi görünecektir:

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);
}

O zaman bir aktivitede nasıl kullanılır? Tür yöntem üzerinden geçirilmeli mi?
skm

Bu Adaptör Aktivitede Nasıl Kullanılır? Ve hangi
türün

20

Farklı düzen için farklı ViewHolder oluşturma

resim açıklamasını buraya girin
RecyclerView istediğiniz sayıda görüntüleyiciye sahip olabilir, ancak daha iyi okunabilirlik için iki ViewHolder ile nasıl oluşturulacağını görelim.

Üç basit adımda yapılabilir

  1. Geçersiz Kıl public int getItemViewType(int position)
  2. ViewType onCreateViewHolder()yöntemine göre farklı ViewHolders döndürme
  3. İçinde itemViewType dayalı Doldur gör onBindViewHolder()yöntemiyle

İşte küçük bir kod snippet'i

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 (int konumu) anahtardır

Bence, bu tür bir recyclerView oluşturmanın başlangıç ​​noktası bu yöntemin bilgisidir. Bu yöntem geçersiz kılmak için isteğe bağlı olduğundan, RecylerView sınıfında varsayılan olarak görünmez, bu da birçok geliştiricinin (ben dahil) nereden başlayacağını merak etmesini sağlar. Bu yöntemin var olduğunu öğrendikten sonra, böyle bir RecyclerView oluşturmak cakewalk olacaktır.

Demek istediğimi kanıtlamak için bir örnek görelim. Alternatif konumlarda iki düzen göstermek istiyorsanız bunu yapın

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

İlgili Bağlantılar:

Bunu uyguladığım projeye göz atın


15

Evet mümkün. Bağdaştırıcınızda getItemViewType Düzeni böyle ....

  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();
        }
    }

referans bağlantısı için: https://www.journaldev.com/12372/android-recyclerview-example


Bu pasajı taklit etmek için kodumu yeniden biçimlendirdim ve şimdi mükemmel çalışıyor. Sahip olduğum sorun tokatlamak geçerli sayfanın ötesinde tokatlamak oldu. Daha fazla çarpışma! Mükemmel model. Teşekkür ederim . Aferin.
user462990

Bunu görene kadar günlerce yararlı bir şey bulamadım, teşekkür ederim!
Itay Braha

7

Anton'un çözümünü takiben, ViewHolderfarklı düzen düzenleri / işleyişleri / delegelere sahip olanı bul. Ancak, geri dönüşüm görünümünün ViewHolderveri aktarma türü olmadığında, yeni mizanpajın değiştirilip değiştirilmeyeceğinden emin değilsiniz.

Temel olarak, onCreateViewHolder(ViewGroup parent, int viewType)yalnızca yeni görünüm düzeni gerektiğinde çağrılır;

getItemViewType(int position)için çağrılacak viewType;

onBindViewHolder(ViewHolder holder, int position)görünüm geri dönüştürülürken her zaman çağrılır (yeni veriler getirilir ve görüntülenmeye çalışılır ViewHolder).

Bu yüzden onBindViewHolderçağrıldığında doğru görünüm düzenini koyup güncellemek gerekir ViewHolder.

ViewHolderGetirilecek görünüm düzenini veya herhangi bir sorunu değiştirmenin yolu doğru mu? Herhangi bir yorum için teşekkür ederiz!

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);
}

Düzenleme: ViewHolder görünümü tutmak için üye mItemViewType üyesi var

Düzenleme: Görünen ViewHolder onBindViewHolder (ViewHolder sahibi, int konumu) gibi görünüyor getItemViewType (int konumu) bir eşleşme olduğundan emin olmak için baktı tarafından alınan (veya oluşturulan), bu yüzden orada ViewHolder endişelenmenize gerek olmayabilir tür, veri [konum] 'un türüyle eşleşmiyor. Herkes onBindViewHolder () ViewHolder nasıl alınır daha fazla biliyor mu?

Edit: Görünüşe göre geri dönüşüm ViewHoldertürüne göre seçilir, bu yüzden orada savaşçı.

Düzenle: http://wiresareobsolete.com/2014/09/building-a-recyclerview-layoutmanager-part-1/ bu soruya cevap veriyor.

Geri dönüşümü şöyle alır ViewHolder:

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

veya geri dönüşüm bulamazsanız yenisini oluşturun ViewHolder doğru türde oluşturun.

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

Açıklayıcı ve güvenli bir şekilde birden çok görünüm türü oluşturmayı sağlayan daha iyi bir çözüm var. Hangi btw gerçekten güzel Kotlin yazılmış.

Gerekli tüm görünüm türleri için basit görünüm tutucular

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
}

Bağdaştırıcı veri öğesinin bir soyutlaması var. Bir görünüm türünün, belirli görünüm tutucu sınıfının bir hashCode'u ile temsil edildiğini unutmayın (Kotlin'de KClass)

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)
   }
}

Sadece bindViewHolderbeton adaptör maddesi sınıflarında geçersiz kılınmalıdır (tip güvenli yol)

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() }
    }
}

Bu tür AdapterItemMediumnesnelerin listesi , bağdaştırıcı için gerçekten kabul eden bir veri kaynağıdır.List<AdapterItem> aşağıya .

Bu çözümün önemli bir kısmı, belirli bir ViewHolder'ın yeni örneklerini sağlayacak bir görünüm tutucu fabrikasıdır

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))
    }
}

Ve basit adaptör sınıfı şöyle görünür

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)     
    }
}

Yeni bir görünüm türü oluşturmak için yalnızca 3 adım:

  1. görünüm tutucu sınıfı oluşturma
  2. bir bağdaştırıcı öğe sınıfı oluşturma (AdapterItemBase öğesinden genişleme)
  3. görünüm sahibi sınıfını kaydet ViewHolderProvider

İşte bu kavramın bir örneği: android-çekmece-şablonu Daha da ileri gider - bir spinner bileşeni, seçilebilir adaptör öğeleri olarak hareket eden görünümü görüntüleyin.


6

Çok basit ve basittir.

Bağdaştırıcınızdaki getItemViewType () yöntemini geçersiz kılın . Verilere dayanarak farklı itemViewType değerleri döndürür. Örneğin, Üyeli isMale türündeki bir nesneyi düşünün, isMale doğruysa, 1 döndürün ve isMale yanlış, getItemViewType () yönteminde 2 döndürün .

Şimdi createViewHolder (ViewGroup üst, int viewType) , farklı viewType yon temelinde farklı düzen dosyasını şişirebilirsiniz. aşağıdaki gibi

 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);
}

içinde onBindViewHolder (VH tutucu, int pozisyon) tutucu örneği olduğu kontrol AdapterFemaleViewHolderya AdapterMaleViewHoldergöre instanceofve buna bağlı olarak değerleri atar.

ViewHolder Böyle olabilir

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

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

4

Seçilen cevap doğru olsa da, sadece daha ayrıntılı olarak ele almak istiyorum. Burada RecyclerView'da birden çok Görünüm Türü için kullanışlı bir Özel Adaptör buldum . Onun Kotlin sürümüne ise buradan .

Özel Adaptör takip ediyor

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

Bu kütüphaneyi Hannes Dorfmann'dan tavsiye ederim. Belirli bir görünüm türüyle ilgili tüm mantığı "AdapterDelegate" adlı ayrı bir nesnede saklar. https://github.com/sockeqwe/AdapterDelegates

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

Aslında, Anton'un cevabını geliştirmek istiyorum .

Yana getItemViewType(int position)döner bir tamsayı değeri, size şişirmek için gerekiyordu düzen kaynak kimliğini döndürebilir. Bu şekilde onCreateViewHolder(ViewGroup parent, int viewType)yöntemde bir mantık kaydedersiniz.

Ayrıca, getItemCount()listeyi oluştururken ve her öğeyi görünür öğelerin ötesinde oluştururken belirli bir işlevin en az 5 kez çağrıldığı için yoğun hesaplamalar yapmanızı önermem . Ne yazık ki notifyDatasetChanged()yöntem son olduğundan, onu geçersiz kılamazsınız, ancak adaptör içindeki başka bir işlevden çağırabilirsiniz.


3
Evet, bu işe yarayabilir, ancak diğer geliştiriciler için kafa karıştırıcı olacaktır. Ayrıca Belgelerden Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.Bu yüzden biraz daha fazla kod yazmak ve kesmek kullanmak daha iyidir.
Ioane Sharvadze

1
Katılıyorum. O zamanlar o maddeyi kaçırmıştım.
Dragas

Bu komik çünkü RecyclerView.Adapter: getItemViewType () burada burada dokümanlar developer.android.com/reference/android/support/v7/widget/… , Dragas'ın yayınladığı öğeyi önerdi. " Görünüşe göre getViewTypeCount () gereksiniminden habersiz
Deemoe

1

Kütüphaneyi kullanabilirsiniz: https://github.com/vivchar/RendererRecyclerViewAdapter

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

'

Her öğe için bir ViewRenderer, ViewHolder, SomeModel uygulamalısınız:

ViewHolder - geri dönüşümcü görünümü basit bir görünüm sahibi.

SomeModel - ItemModelarayüzlü modeliniz

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));
 }
}

Daha fazla bilgi için belgelere bakabilirsiniz.


1

Kotlin ile görünüm türleri uygulaması kolaylaşır, işte bu ışık kütüphanesi ile bir örnek https://github.com/Link184/KidAdapter

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

Beklenen dönüşü RecyclerAdapteryaparak birden fazla ViewTypes yapabilirsinizgetItemViewType()viewType o pozisyon için değeri

Hazırladım MultipleViewTypeAdapter2 veya daha fazla geçerli cevabı (onay kutusu seçenekleri) ve tek bir cevap sorusu (radyo düğmesi seçenekleri) olabilecek bir soru atabilecek sınavlar için MCQ listesi oluşturmak üzere .

Bunun için API yanıtından Soru türü olsun ve ben bu soru için hangi görünümü göstermek zorunda karar vermek için kullanılır.

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();

    }


}

Konumlarına göre onBindViewHolder()farklı olan viewHolders'taki benzer görünümler için aynı kimlikleri atayarak birden fazla koşullu tabanlı viewHolder veri dolgusunu önleyebilirsiniz.


0

Android Veri Bağlama ile birlikte kullanmak istiyorsanız, https://github.com/evant/binding-collection-adapter içine bakın - çoklu görünüm türleri için açık ara en iyi çözümdürRecyclerView gördüğüm .

gibi kullanabilirsin

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

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

ve ardından listenin olduğu düzende

 <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}"/>

liste öğeleriniz BaseListItemşuna benzer bir arayüz uygulamalıdır

interface BaseListItem {
    val layoutRes: Int
}

ve öğe görünümü şöyle görünmelidir

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

    <data>

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

   ...

</layout>

Nerede YourListItemuygularBaseListItem

Umarım birine yardım eder.


0

önce 2 düzen xml oluşturmanız gerekir. bundan sonra, geri dönüşüm görüntüleme adaptörü TYPE_CALL ve TYPE_EMAIL, adaptör sınıfında sırasıyla 1 ve 2 olan iki statik değerdir.

şimdi Recycler view Adapter sınıf düzeyinde iki statik değer tanımlayın, örneğin: private static int TYPE_CALL = 1; özel statik int TYPE_EMAIL = 2;

Şimdi şöyle birden çok görünüme sahip görünüm sahibi oluşturun:

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);
    }
}

Şimdi recyclerview bağdaştırıcısında onCreateViewHolder ve onBindViewHolder yönteminde aşağıdaki gibi kodlayın:

@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));
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.