Recyclerview 및 다양한 유형의 행 인플레이션 처리


124

나는 새로운 작업을 시도하고 RecyclerView있지만 RecyclerView다른 유형의 행 / 카드 뷰가 팽창 되는 예를 찾을 수 없습니다 .

ListViewi를을 무시 getViewTypeCount하고 getItemViewType행의 다른 유형을 처리하기위한.

"오래된"방식으로해야합니까, 아니면 뭔가해야 LayoutManager합니까? 누군가 나를 올바른 방향으로 안내 할 수 있는지 궁금했습니다. 한 가지 유형의 예만 찾을 수 있기 때문입니다.

약간 다른 카드 목록을 갖고 싶습니다. 아니면 내부에 a scrollView를 사용해야합니까 cardViews... 어댑터없이 만드십시오 recyclerView.


아이템 유형의 차이점은 무엇입니까? recyclerview는 다른 유형에 어떻게 반응해야합니까? 일반적으로 recyclerview
로는

실제로 Google Play 스토어에서 보는 것과 같습니다. 상단에는 헤더가 있고 세 개의 카드가 표시되고 정보가있는 섹션이 있습니다. 이것은 recyclerview / listview에서 수행됩니까? 아니면 scrollview? 스크롤 뷰라면 이전에 모든 레이아웃을 결정해야하기 때문입니다. 목록보기를 사용하면 특정 개체를 데이터 세트에 추가 할 수 있으며 올바른 레이아웃이 확장됩니다. 그래서 새로운 Recyclerview로 마지막 부분을 수행하는 방법을 알고 싶습니다. listview와 같은 메서드를 재정의해야합니까?
Lokkio



이 링크를 확인하면 작동 할 수 있습니다.- stackoverflow.com
a/39972276/3946958

답변:


202

iOS의 UITableView와 유사한 행 / 섹션 로직을 처리하는 것은 Android에서 iOS만큼 간단하지는 않지만 RecyclerView를 사용하면 수행 할 수있는 작업의 유연성이 훨씬 더 큽니다.

결국 어댑터에 표시되는보기 유형을 파악하는 방법이 전부입니다. 일단 당신이 그것을 이해했다면, 그것은 쉬운 항해가 될 것입니다 (실제로는 아니지만 적어도 당신은 그것을 분류 할 것입니다).

어댑터는 재정의해야하는 두 가지 메서드를 제공합니다.

getItemViewType(int position)

이 메서드의 기본 구현은 항상 0을 반환하여 뷰 유형이 1 개뿐임을 나타냅니다. 귀하의 경우에는 그렇지 않으므로 어떤 행이 어떤 뷰 유형에 해당하는지 주장하는 방법을 찾아야합니다. 행과 섹션을 사용하여이를 관리하는 iOS와 달리 여기에는 신뢰할 수있는 색인이 하나만 있으며, 위치가 섹션 헤더와 언제 상호 연관되는지, 정상적인 행.

createViewHolder(ViewGroup parent, int viewType)

어쨌든이 메서드를 재정의해야하지만 일반적으로 사람들은 viewType 매개 변수를 무시합니다. 보기 유형에 따라 올바른 레이아웃 리소스를 확장하고 그에 따라보기 홀더를 만들어야합니다. RecyclerView는 서로 다른 뷰 유형의 충돌을 방지하는 방식으로 서로 다른 뷰 유형 재활용을 처리합니다.

와 같은 기본 LayoutManager를 사용할 계획이라면 LinearLayoutManager가야합니다. 자신 만의 LayoutManager 구현을 계획하고 있다면 좀 더 열심히 작업해야합니다. 실제로 작업해야하는 유일한 API findViewByPosition(int position)는 특정 위치에서 주어진 뷰를 제공하는 것입니다. 이 뷰가 어떤 유형 인지에 따라 다르게 레이아웃하고 싶을 것이므로 몇 가지 옵션이 있습니다.

  1. 일반적으로 ViewHolder 패턴을 사용할 때 뷰 홀더를 사용하여 뷰의 태그를 설정합니다. 런타임 동안 레이아웃 관리자에서이를 사용하여이를 표현하는 뷰 홀더에 필드를 추가하여 뷰가 어떤 유형인지 알아낼 수 있습니다.

  2. 어떤 위치가 어떤 뷰 유형과 상관 관계가 있는지를 결정하는 함수가 필요하기 때문에이 메서드를 어떻게 든 전역 적으로 액세스 할 수 있도록 (데이터를 관리하는 싱글 톤 클래스일까요?) 다음에 따라 동일한 메서드를 간단히 쿼리 할 수 ​​있습니다. 위치.

다음은 코드 샘플입니다.

// in this sample, I use an object array to simulate the data of the list. 
// I assume that if the object is a String, it means I should display a header with a basic title.
// If not, I assume it's a custom model object I created which I will use to bind my normal rows.
private Object[] myData;

public static final int ITEM_TYPE_NORMAL = 0;
public static final int ITEM_TYPE_HEADER = 1;

public class MyAdapter extends Adapter<ViewHolder> {

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

        if (viewType == ITEM_TYPE_NORMAL) {
            View normalView = LayoutInflater.from(getContext()).inflate(R.layout.my_normal_row, null);
            return new MyNormalViewHolder(normalView); // view holder for normal items
        } else if (viewType == ITEM_TYPE_HEADER) {
            View headerRow = LayoutInflater.from(getContext()).inflate(R.layout.my_header_row, null);
            return new MyHeaderViewHolder(headerRow); // view holder for header items
        }
    }


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

        final int itemType = getItemViewType(position);

        if (itemType == ITEM_TYPE_NORMAL) {
            ((MyNormalViewHolder)holder).bindData((MyModel)myData[position]);
        } else if (itemType == ITEM_TYPE_HEADER) {
            ((MyHeaderViewHolder)holder).setHeaderText((String)myData[position]);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (myData[position] instanceof String) {
            return ITEM_TYPE_HEADER;
        } else {
            return ITEM_TYPE_NORMAL;
        }
    }

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

다음은 이러한 뷰 보유자가 어떻게 생겼는지에 대한 샘플입니다.

public MyHeaderViewHolder extends ViewHolder {

    private TextView headerLabel;    

    public MyHeaderViewHolder(View view) {
        super(view);

        headerLabel = (TextView)view.findViewById(R.id.headerLabel);
    }

    public void setHeaderText(String text) {
        headerLabel.setText(text);
    }    
}


public MyNormalViewHolder extends ViewHolder {

    private TextView titleLabel;
    private TextView descriptionLabel;    

    public MyNormalViewHolder(View view) {
        super(view);

        titleLabel = (TextView)view.findViewById(R.id.titleLabel);
        descriptionLabel = (TextView)view.findViewById(R.id.descriptionLabel);
    }

    public void bindData(MyModel model) {
        titleLabel.setText(model.getTitle());
        descriptionLabel.setText(model.getDescription());
    }    
}

물론이 샘플에서는 이러한 방식으로 어댑터를 쉽게 구현할 수있는 방식으로 데이터 소스 (myData)를 구성했다고 가정합니다. 예를 들어, 이름 목록과 이름의 첫 번째 글자가 변경 될 때마다 헤더를 표시하는 데이터 소스를 구성하는 방법을 보여 드리겠습니다 (목록이 알파벳순이라고 가정). 목록은 다음과 같습니다.

// Assume names & descriptions are non-null and have the same length.
// Assume names are alphabetized
private void processDataSource(String[] names, String[] descriptions) {
    String nextFirstLetter = "";
    String currentFirstLetter;

    List<Object> data = new ArrayList<Object>();

    for (int i = 0; i < names.length; i++) {
        currentFirstLetter = names[i].substring(0, 1); // get the 1st letter of the name

        // if the first letter of this name is different from the last one, add a header row
        if (!currentFirstLetter.equals(nextFirstLetter)) {
            nextFirstLetter = currentFirstLetter;
            data.add(nextFirstLetter);
        }

        data.add(new MyModel(names[i], descriptions[i]));
    }

    myData = data.toArray();
}

이 예제는 상당히 구체적인 문제를 해결하기 위해 제공되지만 리사이클 러에서 다양한 행 유형을 처리하는 방법에 대한 좋은 개요를 제공하고 필요에 맞게 코드에서 필요한 조정을 수행 할 수 있기를 바랍니다.


꽤 끔찍합니다. 그리고 저는 이것이 그러한 문제를 해결하기위한 훌륭한 샘플이라고 생각합니다. 샘플 솔루션
Amt87

recyelview 내부의 다른 행을 infalting하는 또 다른 예는 다음과 같습니다.- stackoverflow.com
a/39972276/3946958

되어야합니다names[i].substring(0, 1)
Kyle

1
또한 이기종 항목이있는 리사이클 러 뷰의 경우 SpanSizeLookup도 살펴 보는 것이 좋습니다. stackoverflow.com/questions/26869312/…
Mahori

쓸모있다. 이 답변을 기반으로 enum을 사용하여 Adapter에서 다중 유형보기를 구현하는 아이디어도 있습니다. 열거 형에는 onCreateViewHolder뷰 홀더를 만드는 데 도움 이되는 메서드가 있습니다 . 자세한 세부 내용은 내 주 확인 할 수 있습니다 stackoverflow.com/questions/47245398/...
quangson91

114

트릭은 ViewHolder의 하위 클래스를 만든 다음 캐스팅하는 것입니다.

public class GroupViewHolder extends RecyclerView.ViewHolder {
    TextView mTitle;
    TextView mContent;
    public GroupViewHolder(View itemView) {
        super (itemView);
        // init views...
    }
}

public class ImageViewHolder extends RecyclerView.ViewHolder {
    ImageView mImage;
    public ImageViewHolder(View itemView) {
        super (itemView);
        // init views...
    }
}

private static final int TYPE_IMAGE = 1;
private static final int TYPE_GROUP = 2;  

그런 다음 런타임에 다음과 같이하십시오.

@Override
public int getItemViewType(int position) {
    // here your custom logic to choose the view type
    return position == 0 ? TYPE_IMAGE : TYPE_GROUP;
}

@Override
public void onBindViewHolder (ViewHolder viewHolder, int i) {

    switch (viewHolder.getItemViewType()) {

        case TYPE_IMAGE:
            ImageViewHolder imageViewHolder = (ImageViewHolder) viewHolder;
            imageViewHolder.mImage.setImageResource(...);
            break;

        case TYPE_GROUP:
            GroupViewHolder groupViewHolder = (GroupViewHolder) viewHolder;
            groupViewHolder.mContent.setText(...)
            groupViewHolder.mTitle.setText(...);
            break;
    }
}

도움이 되었기를 바랍니다.


3
이것은 질문에 대한 직접적인 대답입니다. 유일한 없어진 부분 (뷰 그룹 부모, INT viewType를) onCreateViewHolder 무시하고 다른보기의 viewType에 따라 유형을 처리 할 필요가있다
user1928896을

인 recyelview 내부의 다른 행을 infalting에 대한 또 다른 예 : - stackoverflow.com/questions/39971350/...
라빈 드라 Kushwaha

1
스위치 케이스 값에 뷰 홀더 기반을 캐스팅하는 대신 일반적인 솔루션이 있습니까?
Vahid Ghadiri

33

Gil에 따르면 Gil이 설명한대로 getItemViewType을 재정 의하여 해결했습니다. 그의 대답은 훌륭하며 올바른 것으로 표시되어야합니다. 어쨌든 점수에 도달하기 위해 코드를 추가합니다.

리사이클 러 어댑터에서 :

@Override
public int getItemViewType(int position) {
    int viewType = 0;
    // add here your booleans or switch() to set viewType at your needed
    // I.E if (position == 0) viewType = 1; etc. etc.
    return viewType;
}

@Override
public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == 0) {
        return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout_for_first_row, parent, false));
    }

    return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_other_rows, parent, false));
}

이렇게하면 모든 행에 대해 사용자 지정 레이아웃을 설정할 수 있습니다!


18
사소한 설명 : onCreateViewHolder의 두 번째 매개 변수는 인덱스가 아닌 viewType이어야합니다. API에 따르면 : developer.android.com/reference/android/support/v7/widget/… , int)
Mark Martinsson 2014

하지만 그 순간에 사용자가 빠르게 스크롤하면 이상한 출력이 나타납니다.
Rjz Satvara

15

꽤 까다 롭지 만 너무 어렵습니다. 아래 코드를 복사하면 완료됩니다.

package com.yuvi.sample.main;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;


import com.yuvi.sample.R;

import java.util.List;

/**
 * Created by yubraj on 6/17/15.
 */

public class NavDrawerAdapter extends RecyclerView.Adapter<NavDrawerAdapter.MainViewHolder> {
    List<MainOption> mainOptionlist;
    Context context;
    private static final int TYPE_PROFILE = 1;
    private static final int TYPE_OPTION_MENU = 2;
    private int selectedPos = 0;
    public NavDrawerAdapter(Context context){
        this.mainOptionlist = MainOption.getDrawableDataList();
        this.context = context;
    }

    @Override
    public int getItemViewType(int position) {
        return (position == 0? TYPE_PROFILE : TYPE_OPTION_MENU);
    }

    @Override
    public MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType){
            case TYPE_PROFILE:
                return new ProfileViewHolder(LayoutInflater.from(context).inflate(R.layout.row_profile, parent, false));
            case TYPE_OPTION_MENU:
                return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.row_nav_drawer, parent, false));
        }
        return null;
    }

    @Override
    public void onBindViewHolder(MainViewHolder holder, int position) {
        if(holder.getItemViewType() == TYPE_PROFILE){
            ProfileViewHolder mholder = (ProfileViewHolder) holder;
            setUpProfileView(mholder);
        }
        else {
            MyViewHolder mHolder = (MyViewHolder) holder;
            MainOption mo = mainOptionlist.get(position);
            mHolder.tv_title.setText(mo.title);
            mHolder.iv_icon.setImageResource(mo.icon);
            mHolder.itemView.setSelected(selectedPos == position);
        }
    }

    private void setUpProfileView(ProfileViewHolder mholder) {

    }

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




public class MyViewHolder extends MainViewHolder{
    TextView tv_title;
    ImageView iv_icon;

    public MyViewHolder(View v){
        super(v);
        this.tv_title = (TextView) v.findViewById(R.id.tv_title);
        this.iv_icon = (ImageView) v.findViewById(R.id.iv_icon);
        v.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Redraw the old selection and the new
                notifyItemChanged(selectedPos);
                selectedPos = getLayoutPosition();
                notifyItemChanged(selectedPos);
            }
        });
    }
}
    public class ProfileViewHolder extends MainViewHolder{
        TextView tv_name, login;
        ImageView iv_profile;

        public ProfileViewHolder(View v){
            super(v);
            this.tv_name = (TextView) v.findViewById(R.id.tv_profile);
            this.iv_profile = (ImageView) v.findViewById(R.id.iv_profile);
            this.login = (TextView) v.findViewById(R.id.tv_login);
        }
    }

    public void trace(String tag, String message){
        Log.d(tag , message);
    }
    public class MainViewHolder extends  RecyclerView.ViewHolder {
        public MainViewHolder(View v) {
            super(v);
        }
    }


}

즐겨 !!!!


My Viewholder1에는 myLaout1.xml이라는 레이아웃이 있고 그 안에 ScrollView가 있습니다. 이제 이걸 스크롤하면 recyclerview가 스크롤됩니다. Viewholder1의 내용을 스크롤하는 방법
Ankesh 쿠마 Jaisansaria

3

아래에서 단일 RecyclerView에 대한 여러 뷰를 얻을 수 있습니다.

Gradle에 대한 종속성이므로 아래 코드를 추가하십시오.

compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'

XML의 RecyclerView

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

활동 코드

private RecyclerView mRecyclerView;
private CustomAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private String[] mDataset = {“Data - one ”, Data - two”,
    Showing data three”, Showing data four”};
private int mDatasetTypes[] = {DataOne, DataTwo, DataThree}; //view types
 
...
 
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(MainActivity.this);
mRecyclerView.setLayoutManager(mLayoutManager);
//Adapter is created in the last step
mAdapter = new CustomAdapter(mDataset, mDataSetTypes);
mRecyclerView.setAdapter(mAdapter);

첫 번째 XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="@dimen/hundered”
    card_view:cardBackgroundColor=“@color/black“>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding=“@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“Fisrt”
            android:textColor=“@color/white“ />
 
        <TextView
            android:id="@+id/temp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textColor="@color/white"
            android:textSize="30sp" />
    </LinearLayout>
 
</android.support.v7.widget.CardView>

두 번째 XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="#00bcd4">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“DataTwo”
            android:textColor="@color/white" />
 
        <TextView
            android:id="@+id/score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textColor="#ffffff"
            android:textSize="30sp" />
    </LinearLayout>
 
</android.support.v7.widget.CardView>

세 번째 XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="@color/white">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“DataThree” />
 
        <TextView
            android:id="@+id/headline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textSize="25sp" />
 
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:id="@+id/read_more"
            android:background="@color/white"
            android:text=“Show More/>
    </LinearLayout>
 
</android.support.v7.widget.CardView>

이제 어댑터를 만들 시간이며 이것은 동일한 리사이클 러 뷰에서 다른 -2 뷰를 표시하는 데 주된 것이므로이 코드 포커스를 완전히 확인하십시오.

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private static final String TAG = "CustomAdapter";
 
    private String[] mDataSet;
    private int[] mDataSetTypes;
 
    public static final int dataOne = 0;
    public static final int dataTwo = 1;
    public static final int dataThree = 2;
 
 
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View v) {
            super(v);
        }
    }
 
    public class DataOne extends ViewHolder {
        TextView temp;
 
        public DataOne(View v) {
            super(v);
            this.temp = (TextView) v.findViewById(R.id.temp);
        }
    }
 
    public class DataTwo extends ViewHolder {
        TextView score;
 
        public DataTwo(View v) {
            super(v);
            this.score = (TextView) v.findViewById(R.id.score);
        }
    }
 
    public class DataThree extends ViewHolder {
        TextView headline;
        Button read_more;
 
        public DataThree(View v) {
            super(v);
            this.headline = (TextView) v.findViewById(R.id.headline);
            this.read_more = (Button) v.findViewById(R.id.read_more);
        }
    }
 
 
    public CustomAdapter(String[] dataSet, int[] dataSetTypes) {
        mDataSet = dataSet;
        mDataSetTypes = dataSetTypes;
    }
 
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View v;
        if (viewType == dataOne) {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.weather_card, viewGroup, false);
 
            return new DataOne(v);
        } else if (viewType == dataTwo) {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.news_card, viewGroup, false);
            return new DataThree(v);
        } else {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.score_card, viewGroup, false);
            return new DataTwo(v);
        }
    }
 
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        if (viewHolder.getItemViewType() == dataOne) {
            DataOne holder = (DataOne) viewHolder;
            holder.temp.setText(mDataSet[position]);
        }
        else if (viewHolder.getItemViewType() == dataTwo) {
            DataThree holder = (DataTwo) viewHolder;
            holder.headline.setText(mDataSet[position]);
        }
        else {
            DataTwo holder = (DataTwo) viewHolder;
            holder.score.setText(mDataSet[position]);
        }
    }
 
    @Override
    public int getItemCount() {
        return mDataSet.length;
    }
 
   @Override
    public int getItemViewType(int position) {
        return mDataSetTypes[position];
    }
}

자세한 내용 은이 링크 를 확인하십시오.


하지만 그것은 잘 작동하지만 위에서 아래로 빠르게 스크롤하고 그 반대의 경우도 이상한 출력을 얻고 있습니다 ... 데이터가 적절하게 설정되지 않았 음을 의미합니다. 그 해결책은 무엇입니까?
Rjz Satvara

2

.NET에서 getItemViewType()메서드 를 구현해야합니다 RecyclerView.Adapter. 기본적 으로이 메서드를 onCreateViewHolder(ViewGroup parent, int viewType)구현 viewType하면 0. 먼저 뷰 재활용을 위해 위치에있는 항목의 뷰 유형이 필요하며이를 위해서는 항목의 위치를 반환하는 getItemViewType()통과 할 수있는 메서드 를 재정의해야합니다 viewType. 코드 샘플은 다음과 같습니다.

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

@Override
public int getItemViewType(int position) {   
    return position;
}

// and in the similar way you can set data according 
// to view holder position by passing position in getItemViewType
@Override
public void onBindViewHolder(MyViewholder viewholder, int position) {
    int listViewItemType = getItemViewType(position);
    // ...
}

2

getItemViewType (int position)은 키입니다.

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

여기에 이미지 설명 입력

어떻게하나요?

RecyclerView원하는 수의 다른 뷰 (ViewHolders)를 만들 수 있습니다 . 그러나 더 나은 가독성을 위해 RecyclerView두 개의 Viewholders.
3 가지 간단한 단계를 기억하십시오 .

  • public int 재정의 getItemViewType(int position)
  • ViewTypein onCreateViewHolder () 메서드를 기반으로 다른 ViewHolders 반환
  • 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
           }
      }
    }

GitHub 코드 :

다음은 여러 ViewHolders가있는 RecyclerView를 구현 한 프로젝트 입니다.


동일하지만 여러 데이터 세트를 갖는 것은 어떻습니까?
esQmo_

무슨 말이야? @esQmo_
로힛 싱

모든 참가자가 다른 데이터 세트 (데이터 소스)를 가지고 있다면 어떨까요?
esQmo_

1

ItemViewType을 반환하고 사용할 수 있습니다. 아래 코드를 참조하십시오.

@Override
public int getItemViewType(int position) {

    Message item = messageList.get(position);
    // return my message layout
    if(item.getUsername() == Message.userEnum.I)
        return R.layout.item_message_me;
    else
        return R.layout.item_message; // return other message layout
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(viewType, viewGroup, false);
    return new ViewHolder(view);
}

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

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


0

이 라이브러리를 사용할 수 있습니다 :
https://github.com/kmfish/MultiTypeListViewAdapter (내가 작성)

  • 한 셀의 코드를 더 잘 재사용
  • 더 나은 확장
  • 더 나은 디커플링

설치 어댑터 :

adapter = new BaseRecyclerAdapter();
adapter.registerDataAndItem(TextModel.class, LineListItem1.class);
adapter.registerDataAndItem(ImageModel.class, LineListItem2.class);
adapter.registerDataAndItem(AbsModel.class, AbsLineItem.class);

각 광고 항목에 대해 :

public class LineListItem1 extends BaseListItem<TextModel, LineListItem1.OnItem1ClickListener> {

    TextView tvName;
    TextView tvDesc;


    @Override
    public int onGetLayoutRes() {
        return R.layout.list_item1;
    }

    @Override
    public void bindViews(View convertView) {
        Log.d("item1", "bindViews:" + convertView);
        tvName = (TextView) convertView.findViewById(R.id.text_name);
        tvDesc = (TextView) convertView.findViewById(R.id.text_desc);

        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != attachInfo) {
                    attachInfo.onNameClick(getData());
                }
            }
        });
        tvDesc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != attachInfo) {
                    attachInfo.onDescClick(getData());
                }
            }
        });

    }

    @Override
    public void updateView(TextModel model, int pos) {
        if (null != model) {
            Log.d("item1", "updateView model:" + model + "pos:" + pos);
            tvName.setText(model.getName());
            tvDesc.setText(model.getDesc());
        }
    }

    public interface OnItem1ClickListener {
        void onNameClick(TextModel model);
        void onDescClick(TextModel model);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.