Recyclerview とさまざまな種類の行インフレーションの処理 質問する

Recyclerview とさまざまな種類の行インフレーションの処理 質問する

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

Iでは、異なるタイプの行を処理するために、およびをListViewオーバーライドします。getViewTypeCountgetItemViewType

「古い」方法のように行うべきでしょうか、それとも を使って何かを行うべきでしょうかLayoutManager? 誰かが私に正しい方向を指し示してくれるかどうか疑問に思っています。 1 つのタイプの例しか見つからないからです。

少しだけ異なるカードのリストが欲しいです。それとも、内部に を使用scrollViewした を使用するだけでいいのでしょうかcardViews...アダプタと なしで作成しますrecyclerViewか?

ベストアンサー1

iOS の UITableView に似た行/セクションのロジックを処理することは、Android では iOS ほど簡単ではありませんが、RecyclerView を使用すると、実行できる柔軟性がはるかに高くなります。

結局のところ、アダプタに表示するビューの種類をどうやって決めるかが重要です。それを理解すれば、あとは楽なはずです (実際はそうではありませんが、少なくとも整理はできます)。

アダプタはオーバーライドする必要がある 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();
}

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

おすすめ記事