128

新しい を使用しようとしていますが、さまざまなタイプの行/カードビューが膨張してRecyclerViewいる例を見つけることができませんでした。RecyclerView

で、さまざまな種類の行を処理するためにandListViewをオーバーライドします。getViewTypeCountgetItemViewType

「古い」方法のようにそれを行うべきですか、それとも何かを行う必要がありLayoutManagerますか? 誰かが私を正しい方向に向けることができるかどうか疑問に思っていました。1 つのタイプの例しか見つからないためです。

少し違うカードのリストが欲しいです。または、その中にあるものscrollViewを使用する必要cardViewsがあります...アダプターなしで作成しrecyclerViewますか?

4

10 に答える 10

207

iOS の UITableView に似た行/セクション ロジックの処理は、iOS ほど単純ではありませんが、RecyclerView を使用すると、できることの柔軟性が大幅に向上します。

最終的には、Adapter に表示しているビューのタイプをどのように把握するかがすべてです。それが分かれば、簡単に航海できるはずです(実際にはそうではありませんが、少なくともそれを整理することはできます)。

Adapter は、オーバーライドする必要がある 2 つのメソッドを公開します。

getItemViewType(int position)

このメソッドのデフォルトの実装は常に 0 を返します。これは、ビューのタイプが 1 つしかないことを示します。あなたの場合はそうではないので、どの行がどのビュータイプに対応するかをアサートする方法を見つける必要があります。行とセクションでこれを管理する iOS とは異なり、ここでは依存するインデックスが 1 つしかないため、開発者のスキルを使用して、位置がセクション ヘッダーにいつ相関し、いつセクション ヘッダーに相関するかを知る必要があります。通常の列。

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

この例はかなり具体的な問題を解決するためのものですが、リサイクラーでさまざまな行の型を処理する方法の概要がわかり、ニーズに合わせて独自のコードに必要な調整を加えることができることを願っています。

于 2014-09-21T14:15:50.557 に答える
34

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

これにより、任意の行に任意のカスタム レイアウトを設定できます。

于 2014-11-17T09:46:26.133 に答える
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);
        }
    }


}

楽しい !!!!

于 2015-08-28T09:17:26.770 に答える
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“&gt;
 
    <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>

2 番目の 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>

3 番目の 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];
    }
}

詳細については、このリンクも確認できます。

于 2016-04-28T09:50:14.203 に答える
2

getItemViewType()でメソッドを実装する必要がありRecyclerView.Adapterます。デフォルトでは、このメソッドのonCreateViewHolder(ViewGroup parent, int viewType)実装は を返します。まず、ビューのリサイクルのために、その位置にあるアイテムのビュー タイプが必要です。そのためには、アイテムの位置を返す、渡すことができるメソッドをオーバーライドする必要があります。コードサンプルを以下に示しますviewType0getItemViewType()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);
    // ...
}
于 2015-03-25T12:40:22.337 に答える
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);
}
于 2015-05-14T09:30:49.067 に答える