다중보기 유형으로 RecyclerView를 만드는 방법은 무엇입니까?


864

에서 https://developer.android.com/preview/material/ui-widgets.html

생성 RecyclerView.Adapter할 때 ViewHolder어댑터와 바인딩 할 것을 지정해야 합니다.

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

그렇다면 RecyclerView여러보기 유형 으로 만들 수 있습니까?


5
안톤의 대답의 위에, 여기 내 대답을 참조하십시오 stackoverflow.com/questions/25914003/...
ticofab

당신을 위해 유용 수도 있습니다 이러한 링크를 확인 stackoverflow.com/a/39972276/3946958
라빈 드라 Kushwaha

1
좋은 튜토리얼 : guides.codepath.com/android/…
Gene Bo

그것이 가능한 것입니다 이러한 링크를 확인 stackoverflow.com/questions/39971350/... 알려 주시기 바랍니다보다는 문제가있는 경우
라빈 드라 Kushwaha

그것을 구현하는 위대한 도서관 github.com/vivchar/RendererRecyclerViewAdapter
Vitaly

답변:


1269

네 가능합니다. getItemViewType ()을 구현 하고의 viewType매개 변수를 처리하십시오 onCreateViewHolder().

그래서 당신은 다음과 같은 일을합니다 :

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
하나의 RecyclerView에서 하나의 ViewHolder 만 사용할 수 있기 때문에 내 요점입니다. 어댑터에 여러 개를 추가하는 방법은 무엇입니까?
Pongpat

48
그런 다음 onBindViewHolder () 메소드에서 뷰 홀더 유형을 캐스트해야합니다. 제네릭 유형의 목적을 무효화한다고 생각합니다. 그건 그렇고, 답변 주셔서 감사합니다.
Pongpat

32
BaseHolder를 작성하여 필요한 모든 유형으로 확장 할 수 있습니다. 그런 다음 구현 홀더에서 재정의되는 (overrode?) 추상 setData를 추가하십시오. 이런 식으로 언어가 유형 차이를 처리하게합니다. 모든 목록 항목이 해석 할 수있는 단일 데이터 세트가있는 경우에만 작동합니다.
DariusL

2
다른 레이아웃 파일은 어떻습니까? 의 레이아웃을 변경하고 싶습니다 optionMenuItem. 어떻게 가능합니까? @AntonSavin
Pratik Butani

5
ViewHolders가 RecyclerView 어댑터에 있으면 정적이어야합니다.
Samer

88

뷰 유형의 레이아웃이 적고 바인딩 로직이 간단한 경우 Anton의 솔루션을 따르십시오.
그러나 복잡한 레이아웃과 바인딩 로직을 관리해야하는 경우 코드가 지저분해질 것입니다.

다음 솔루션이 복잡한보기 유형을 처리 해야하는 사람에게 유용 할 것이라고 생각합니다.

기본 DataBinder 클래스

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

......

}

이 클래스에서 정의하는 데 필요한 함수는 단일보기 유형을 작성할 때 어댑터 클래스와 거의 동일합니다.
각 뷰 유형에 대해이 DataBinder를 확장하여 클래스를 작성하십시오.

샘플 DataBinder 클래스

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 클래스를 관리하려면 어댑터 클래스를 작성하십시오.

기본 DataBindAdapter 클래스

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

......

}

이 기본 클래스를 확장하여 클래스를 작성한 다음 DataBinder 클래스를 인스턴스화하고 추상 메소드를 대체하십시오.

  1. getItemCount
    DataBinder의 총 항목 수를 반환합니다.

  2. getItemViewType
    어댑터 위치와보기 유형 사이의 맵핑 논리를 정의하십시오.

  3. getDataBinder
    뷰 타입에 따라 DataBinder 인스턴스를 반환

  4. getPosition
    지정된 DataBinder의 위치에서 변환 논리를 어댑터 위치로 정의

  5. getBinderPosition
    어댑터 위치에서 DataBinder의 위치로 변환 논리를 정의하십시오.

이 솔루션이 도움이 되길 바랍니다.
더 자세한 솔루션과 샘플을 GitHub에 남겨 두었으므로 필요한 경우 다음 링크를 참조하십시오.
https://github.com/yqritc/RecyclerView-MultipleViewTypesAdapter


4
나는 당신의 코드에 약간 혼란 스럽습니다. 어쩌면 당신이 나를 도울 수 있습니다. 내보기가 목록의 위치에 의해 정의되는 것이 아니라보기 유형에 의해 정의되기를 바랍니다. 마치 코드의 뷰가 위치에 따라 결정되는 것처럼 보입니다. 따라서 위치 1에 im이 있으면보기 1이 표시되고 위치 3,보기 3이 표시되고 나머지는 모두 위치 2의보기를 표시합니다. 뷰의 위치를 ​​기준으로하지 않고 뷰 유형을 기반으로하고 싶지 않습니다. 따라서 뷰 유형을 이미지로 지정하면 이미지가 표시되어야합니다. 어떻게해야합니까?
Simon

죄송합니다, 귀하의 질문을 완전히 이해할 수 없었습니다 ... 그러나 위치와 뷰 타입을 바인딩하려면 어딘가에 논리를 작성해야합니다.
yqritc

1
이 코드는 혼란스럽지 않고 RecyclerView 어댑터 패턴이며 질문에 대한 정답처럼 제외되어야합니다. @yqritc의 링크를 따라 약간의 시간을 들여 발견하면 다양한 유형의 레이아웃으로 RecyclerView에 대한 완벽한 패턴을 갖게됩니다.
Stoycho Andreev

여기에 public class DataBinder<T extends RecyclerView.ViewHolder>누군가가 무엇 <T someClass>이라 불리는 지 말해 줄 수 있으므로 용어를 얻으면 Google을 사용할 수 있습니다. 또한 내가 말할 abstract public class DataBinder<T extends RecyclerView.ViewHolder>때이 클래스는 유형이라는 것을 의미 ViewHolder하므로 결과적 으로이 클래스를 확장하는 모든 클래스 viewHolder는 아이디어 유형 입니까?
rgv

1
@cesards 당신이 다형성 롤리에 대한 지식을 다시 새로 고치도록 만들었습니다 .... Java는 나쁘지 않습니다
Paul Okeke

37

아래는 의사 코드가 아니며 테스트했으며 저에게 효과적입니다.

내 recyclerview에서 headerview를 만들고 헤더 아래에 사용자가 클릭 할 수있는 그림 목록을 표시하고 싶었습니다.

내 코드에서 몇 가지 스위치를 사용했는데 이것이 가장 효율적인 방법인지 모르겠으므로 의견을 말해주십시오.

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

        }
    }

동적 위치에서 여러 헤더를 원한다면 어떻게 될까요? 카테고리를 정의하는 헤더가있는 항목 목록을 가정 해 보겠습니다. 해결책은 특수 헤더가 미리 결정된 int 위치에 있어야하는 것 같습니다.
Bassinator

22

네 가능합니다.

일반적인 뷰 홀더를 작성하십시오.

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

    public abstract  void setDataOnView(int position);
}

그런 다음 뷰 홀더를 만들어 GenericViewHolder를 확장하십시오. 예를 들면 다음과 같습니다.

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

RecyclerView.Adapter 클래스는 다음과 같습니다.

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

활동에서 어떻게 사용합니까? 메소드를 통해 유형을 전달해야합니까?
skm

활동에서이 어댑터를 사용하는 방법은 무엇입니까? 그리고 목록에 어떤 유형이 있는지 인식하는 방법
skm

20

다른 레이아웃에 대해 다른 ViewHolder 생성

여기에 이미지 설명을 입력하십시오
RecyclerView는 원하는 수의 뷰 홀더를 가질 수 있지만 가독성을 높이기 위해 두 개의 ViewHolders로 뷰 홀더를 작성하는 방법을 볼 수 있습니다.

세 가지 간단한 단계로 수행 할 수 있습니다

  1. 우세하다 public int getItemViewType(int position)
  2. 의 ViewType에 따라 서로 다른 ViewHolders 반환 onCreateViewHolder()방법
  3. onBindViewHolder()메소드 의 itemViewType을 기반으로 뷰 채우기

다음은 작은 코드 스 니펫입니다.

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 position)이 키입니다

내 의견으로는, 이런 종류의 recyclerView를 만드는 출발점은이 방법에 대한 지식입니다. 이 방법은 재정의하는 선택 사항이므로 기본적으로 RecylerView 클래스에는 표시되지 않으므로 많은 개발자 (나를 포함하여)가 어디서부터 시작 해야하는지 궁금해합니다. 이 방법이 존재한다는 것을 알고 나면 이러한 RecyclerView를 만드는 것이 케이크가 될 것입니다.

내 요점을 증명하는 한 가지 예를 보자. 다른 위치에 두 개의 레이아웃을 표시하려면 다음을 수행하십시오.

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

관련 링크 :

내가 이것을 구현 한 프로젝트를 확인하십시오.


15

네 가능합니다. 어댑터에서 다음과 같이 getItemViewType Layout ....

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

참조 링크 : https://www.journaldev.com/12372/android-recyclerview-example


이 스 니펫을 모방하기 위해 코드를 다시 포맷했으며 이제는 완벽하게 작동합니다. 내가 겪고있는 문제는 현재 페이지 너머로 스 와이프하면 충돌한다는 것입니다. 더 이상 충돌하지 마십시오! 뛰어난 모델. 감사합니다 . 잘 했어.
user462990

내가 이것을 볼 때까지 며칠 동안 도움이 될만한 것을 찾을 수 없었습니다. 감사합니다!
Itay Braha

7

Anton의 솔루션에 ViewHolder따라 다양한 유형의 레이아웃을 보유 / 처리 / 위임하는 이 를 생각해보십시오 . 그러나 재활용보기 ViewHolder가 데이터 롤 유형이 아닌 경우 새 레이아웃 교체가 작동하는지 확실 하지 않습니다.

따라서 기본적으로 onCreateViewHolder(ViewGroup parent, int viewType)새로운 뷰 레이아웃이 필요할 때만 호출됩니다.

getItemViewType(int position)를 요구할 것이다 viewType;

onBindViewHolder(ViewHolder holder, int position)뷰를 재활용 할 때 항상 호출됩니다 (새 데이터를 가져 와서 표시하려고 시도 ViewHolder).

따라서 onBindViewHolder호출되면 올바른 뷰 레이아웃을 배치하고을 업데이트해야합니다 ViewHolder.

ViewHolder가져올 뷰 레이아웃을 바꾸 거나 문제가 발생 하는 올바른 방법 입니까? 의견을 보내주세요!

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

편집 : ViewHolder에는 mItemViewType 멤버가있어보기를 보유합니다.

편집 : onBindViewHolder (ViewHolder holder, int position)에서 보이는 것처럼 ViewHolder가 getItemViewType (int position)을보고 일치하는지 확인하여 일치 시키므로 ViewHolder가 걱정할 필요가 없습니다. type이 data [position]의 유형과 일치하지 않습니다. 누구든지 onBindViewHolder ()의 ViewHolder가 어떻게 선택되는지 알고 있습니까?

편집 : 재활용 ViewHolder이 유형별로 선택되므로 전사가 없습니다.

편집 : http://wiresareobsolete.com/2014/09/building-a-recyclerview-layoutmanager-part-1/ 이 질문에 답변합니다.

다음 ViewHolder과 같이 재활용됩니다 .

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

ViewHolder올바른 유형의 재활용품 을 찾지 못하면 새 제품을 만드십시오 .

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

선언적이고 안전한 방식으로 여러보기 유형을 만들 수있는 더 나은 솔루션이 있습니다. btw가 정말 좋은 Kotlin으로 작성되었습니다.

모든 필요한 뷰 유형에 대한 간단한 뷰 홀더

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
}

어댑터 데이터 항목의 추상화가 있습니다. 뷰 유형은 특정 뷰 홀더 클래스의 해시 코드로 표시됩니다 (Ktlin의 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)
   }
}

bindViewHolder구체적인 어댑터 항목 클래스 에서만 재정의해야합니다 (유형 안전 방식).

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

이러한 AdapterItemMedium오브젝트 목록은 실제로 어댑터의 데이터 소스이며 List<AdapterItem>아래를 참조하십시오.

이 솔루션의 중요한 부분은 특정 ViewHolder의 새로운 인스턴스를 제공하는 뷰 홀더 팩토리입니다.

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

그리고 간단한 어댑터 클래스는 다음과 같습니다

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

새보기 유형을 작성하는 3 단계 만 있습니다.

  1. 뷰 홀더 클래스 만들기
  2. 어댑터 항목 클래스 작성 (AdapterItemBase에서 확장)
  3. 뷰 홀더 클래스 등록 ViewHolderProvider

이 개념의 예는 다음과 같습니다. android-drawer-template 더 나아가서 스피너 구성 요소, 선택 가능한 어댑터 항목으로 작동하는 뷰 유형입니다.


6

매우 간단하고 간단합니다.

어댑터에서 getItemViewType () 메소드를 대체 하십시오. 데이터를 기반으로 다른 itemViewType 값을 반환합니다. 예를 들어, isMale 멤버가있는 Person 유형의 오브젝트를 고려하십시오. isMale이 true이면 1을 리턴하고 isMale이 false이면 getItemViewType () 메소드 에서 2를 리턴하십시오 .

이제 다른 viewType을 기반으로 createViewHolder (ViewGroup parent, int viewType) 가 다른 레이아웃 파일을 팽창시킬 수 있습니다. 다음과 같이

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

onBindViewHolder (VH 홀더 INT 위치) 홀더의 인스턴스이고 확인 AdapterFemaleViewHolder하거나 AdapterMaleViewHolder하여이 instanceof따라 값을 할당한다.

ViewHolder 다음과 같이 될 수 있습니다

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

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

4

선택한 답변은 정확하지만 더 자세히 설명하고 싶습니다. 여기서는 RecyclerView의 여러보기 유형에 유용한 사용자 정의 어댑터를 찾았습니다 . 그것의 코 틀린 버전은 여기에있다 .

커스텀 어댑터 팔로우

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

Hannes Dorfmann의이 라이브러리를 추천합니다. "AdapterDelegate"라는 별도의 개체에 특정 뷰 유형과 관련된 모든 논리를 캡슐화합니다. 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

사실, 나는 Anton의 대답 을 개선하고 싶습니다 .

getItemViewType(int position)정수 값을 반환 하므로 팽창해야하는 레이아웃 리소스 ID를 반환 할 수 있습니다. 그렇게하면 몇 가지 논리를 onCreateViewHolder(ViewGroup parent, int viewType)방법으로 저장할 수 있습니다 .

또한 getItemCount()목록을 렌더링 할 때뿐만 아니라 각 항목을 보이는 항목 이상으로 렌더링하는 동안 특정 함수가 적어도 5 번 호출되므로 집중적 인 계산을 수행하지 않는 것이 좋습니다 . 안타깝게도 notifyDatasetChanged()method가 final이므로 실제로 재정의 할 수는 없지만 어댑터 내의 다른 함수에서 호출 할 수 있습니다.


3
예, 작동하지만 다른 개발자에게는 혼란을 줄 것입니다. 또한 Documentation에서 Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE can also be returned.더 많은 코드를 작성하고 해킹을 사용하지 않는 것이 좋습니다.
Ioane Sharvadze

1
동의한다. 그때 나는 그 특정 조항을 놓쳤다.
Dragas

RecyclerView.Adapter : getItemViewType () docs developer.android.com/reference/android/support/v7/widget/… 문서가 있기 때문에 재미 있습니다. Dragas 가 게시 한 내용을 제안합니다. " getViewTypeCount ()에 대한 요구 사항을 분명히 알지 못함
Deemoe

1

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 */

`

각 항목에 대해 ViewRenderer, ViewHolder, SomeModel을 구현해야합니다.

ViewHolder-리사이클 뷰의 간단한 뷰 홀더입니다.

SomeModel- ItemModel인터페이스 가있는 모델입니다

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

자세한 내용은 설명서를 참조하십시오.


1

보기 유형의 구현은 여기, 코 틀린에 쉽게된다이 빛 라이브러리와 샘플입니다 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

해당 위치 의 예상 값을 반환하여 multipleViewTypes RecyclerAdapter를 처리 할 수 ​​있습니다getItemViewType()viewType

MultipleViewTypeAdapter2 개 이상의 유효한 답변 (확인란 옵션)과 단일 답변 질문 (라디오 버튼 옵션)이있을 수있는 질문을 던질 수있는 시험을위한 MCQ 목록 구성을 준비했습니다 .

이를 위해 API 응답에서 Question 유형을 가져오고 해당 질문에 대해 표시 해야하는보기를 결정하는 데 사용했습니다.

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

    }


}

onBindViewHolder()위치가 다른 viewHolders에서 유사한보기에 대해 동일한 ID를 지정하여 여러 조건 기반 viewHolder 데이터가 채워지지 않도록 할 수 있습니다 .


0

Android Data Binding과 함께 사용하려면 https://github.com/evant/binding-collection-adapter를 살펴보십시오. 지금까지 본 여러보기 유형에 가장 적합한 솔루션입니다 RecyclerView.

당신은 그것을 사용할 수 있습니다

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

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

그런 다음 list가있는 레이아웃에서

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

목록 항목은 BaseListItem다음과 같은 인터페이스를 구현해야합니다.

interface BaseListItem {
    val layoutRes: Int
}

항목보기는 다음과 같아야합니다.

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

    <data>

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

   ...

</layout>

YourListItem구현하는 곳BaseListItem

누군가에게 도움이되기를 바랍니다.


0

먼저 2 개의 레이아웃 xml을 작성해야합니다. 그 후 recyclerview 어댑터 내부에서 TYPE_CALL 및 TYPE_EMAIL은 어댑터 클래스에서 각각 1과 2를 갖는 두 개의 정적 값입니다.

이제 Recycler 뷰 어댑터 클래스 레벨에서 두 개의 정적 값을 정의하십시오. 예 : private static int TYPE_CALL = 1; private static int TYPE_EMAIL = 2;

이제 다음과 같이 여러 개의 뷰로 뷰 홀더를 만듭니다.

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

이제 recyclerview 어댑터의 onCreateViewHolder 및 onBindViewHolder 메소드에서 아래와 같이 코딩하십시오.

@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));
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.